tiptap/docs/guide/node-views/vue.md

230 lines
5.8 KiB
Markdown
Raw Normal View History

---
tableOfContents: true
---
2021-03-18 05:35:41 +08:00
# Node views with Vue
## Introduction
2021-04-16 03:48:19 +08:00
Using Vanilla JavaScript can feel complex if you are used to work in Vue. Good news: You can use regular Vue components in your node views, too. There is just a little bit you need to know, but lets go through this one by one.
2021-03-18 05:35:41 +08:00
## Render a Vue component
2021-04-03 22:13:47 +08:00
Here is what you need to do to render Vue components inside your editor:
2021-03-18 05:35:41 +08:00
2021-04-07 05:36:07 +08:00
1. [Create a node extension](/guide/custom-extensions)
2021-03-18 05:35:41 +08:00
2. Create a Vue component
3. Pass that component to the provided `VueNodeViewRenderer`
4. Register it with `addNodeView()`
2021-10-20 04:30:45 +08:00
5. [Configure Tiptap to use your new node extension](/guide/configuration)
2021-03-18 05:35:41 +08:00
This is how your node extension could look like:
```js
import { Node } from '@tiptap/core'
import { VueNodeViewRenderer } from '@tiptap/vue-2'
import Component from './Component.vue'
export default Node.create({
// configuration …
addNodeView() {
return VueNodeViewRenderer(Component)
},
})
```
There is a little bit of magic required to make this work. But dont worry, we provide a wrapper component you can use to get started easily. Dont forget to add it to your custom Vue component, like shown below:
```html
<template>
<node-view-wrapper>
Vue Component
</node-view-wrapper>
</template>
```
Got it? Lets see it in action. Feel free to copy the below example to get started.
2021-10-19 00:01:47 +08:00
https://embed.tiptap.dev/preview/GuideNodeViews/VueComponent
2021-03-18 05:35:41 +08:00
2021-04-03 22:13:47 +08:00
That component doesnt interact with the editor, though. Time to wire it up.
2021-03-18 05:35:41 +08:00
## Access node attributes
2021-04-03 22:49:53 +08:00
The `VueNodeViewRenderer` which you use in your node extension, passes a few very helpful props to your custom Vue component. One of them is the `node` prop. Add this snippet to your Vue component to directly access the node:
2021-03-18 05:35:41 +08:00
```js
props: {
node: {
type: Object,
required: true,
},
},
```
2021-05-05 05:59:34 +08:00
That enables you to access node attributes in your Vue component. Lets say you have [added an attribute](/guide/custom-extensions#attributes) named `count` to your node extension (like we did in the above example) you could access it like this:
2021-03-18 05:35:41 +08:00
```js
this.node.attrs.count
```
## Update node attributes
You can even update node attributes from your node, with the help of the `updateAttributes` prop passed to your component. Just add this snippet to your component:
```js
props: {
updateAttributes: {
type: Function,
required: true,
},
},
```
Pass an object with updated attributes to the function:
```js
this.updateAttributes({
count: this.node.attrs.count + 1,
})
```
2023-05-18 20:37:13 +08:00
And yes, all of that is reactive, too. A pretty seamless communication, isnt it?
2021-03-18 05:35:41 +08:00
## Adding a content editable
There is another component called `NodeViewContent` which helps you adding editable content to your node view. Here is an example:
```html
<template>
<node-view-wrapper class="dom">
<node-view-content class="content-dom" />
</node-view-wrapper>
</template>
<script>
import { NodeViewWrapper, NodeViewContent } from '@tiptap/vue-2'
export default {
components: {
NodeViewWrapper,
NodeViewContent,
},
}
2021-03-25 06:24:37 +08:00
</script>
2021-03-18 05:35:41 +08:00
```
You dont need to add those `class` attributes, feel free to remove them or pass other class names. Try it out in the following example:
2021-10-19 00:01:47 +08:00
https://embed.tiptap.dev/preview/GuideNodeViews/VueComponentContent
2021-03-18 05:35:41 +08:00
2021-10-20 04:30:45 +08:00
Keep in mind that this content is rendered by Tiptap. That means you need to tell what kind of content is allowed, for example with `content: 'inline*'` in your node extension (thats what we use in the above example).
2021-03-18 05:35:41 +08:00
The `NodeViewWrapper` and `NodeViewContent` components render a `<div>` HTML tag (`<span>` for inline nodes), but you can change that. For example `<node-view-content as="p">` should render a paragraph. One limitation though: That tag must not change during runtime.
## All available props
For advanced use cases, we pass a few more props to the component.
### editor
The editor instance.
### node
Access the current node.
### decorations
An array of decorations.
### selected
`true` when there is a `NodeSelection` at the current node view.
### extension
Access to the node extension, for example to get options.
### getPos()
Get the document position of the current node.
### updateAttributes()
Update attributes of the current node.
### deleteNode()
Delete the current node.
Here is the full list of what props you can expect:
2021-03-18 05:35:41 +08:00
```html
<template>
<node-view-wrapper />
</template>
<script>
import { NodeViewWrapper } from '@tiptap/vue-2'
export default {
components: {
NodeViewWrapper,
},
props: {
// the editor instance
editor: {
type: Object,
},
// the current node
node: {
type: Object,
},
// an array of decorations
decorations: {
type: Array,
},
2021-05-19 06:03:20 +08:00
// `true` when there is a `NodeSelection` at the current node view
2021-03-18 05:35:41 +08:00
selected: {
type: Boolean,
},
// access to the node extension, for example to get options
extension: {
type: Object,
},
// get the document position of the current node
getPos: {
type: Function,
},
// update attributes of the current node
updateAttributes: {
type: Function,
},
// delete the current node
deleteNode: {
type: Function,
},
2021-03-18 05:35:41 +08:00
},
}
</script>
```
2021-03-19 04:58:23 +08:00
If you just want to have all (and TypeScript support) you can import all props like that:
2021-03-19 04:58:23 +08:00
```js
// Vue 3
import { defineComponent } from 'vue'
import { nodeViewProps } from '@tiptap/vue-3'
export default defineComponent({
props: nodeViewProps,
})
// Vue 2
import Vue from 'vue'
import { nodeViewProps } from '@tiptap/vue-2'
export default Vue.extend({
props: nodeViewProps,
})
```
## Dragging
To make your node views draggable, set `draggable: true` in the extension and add `data-drag-handle` to the DOM element that should function as the drag handle.
2021-10-19 00:01:47 +08:00
https://embed.tiptap.dev/preview/GuideNodeViews/DragHandle