mirror of
https://github.com/ueberdosis/tiptap.git
synced 2024-11-27 14:59:27 +08:00
revert: "fix(vue-3): faster component rendering (#5206)"
This reverts commit 31f3746491
.
This commit is contained in:
parent
dbab8e42ea
commit
ff04353b3e
@ -1,14 +1,16 @@
|
||||
import { Editor as CoreEditor, EditorOptions } from '@tiptap/core'
|
||||
import { EditorState, Plugin, PluginKey } from '@tiptap/pm/state'
|
||||
import {
|
||||
AppContext,
|
||||
ComponentInternalInstance,
|
||||
ComponentPublicInstance,
|
||||
customRef,
|
||||
markRaw,
|
||||
reactive,
|
||||
Ref,
|
||||
} from 'vue'
|
||||
|
||||
import { VueRenderer } from './VueRenderer.js'
|
||||
|
||||
function useDebouncedRef<T>(value: T) {
|
||||
return customRef<T>((track, trigger) => {
|
||||
return {
|
||||
@ -40,9 +42,9 @@ export class Editor extends CoreEditor {
|
||||
|
||||
private reactiveExtensionStorage: Ref<Record<string, any>>
|
||||
|
||||
public contentComponent: ContentComponent | null = null
|
||||
public vueRenderers = reactive<Map<string, VueRenderer>>(new Map())
|
||||
|
||||
public appContext: AppContext | null = null
|
||||
public contentComponent: ContentComponent | null = null
|
||||
|
||||
constructor(options: Partial<EditorOptions> = {}) {
|
||||
super(options)
|
||||
|
@ -1,4 +1,5 @@
|
||||
import {
|
||||
DefineComponent,
|
||||
defineComponent,
|
||||
getCurrentInstance,
|
||||
h,
|
||||
@ -7,6 +8,7 @@ import {
|
||||
PropType,
|
||||
Ref,
|
||||
ref,
|
||||
Teleport,
|
||||
unref,
|
||||
watchEffect,
|
||||
} from 'vue'
|
||||
@ -43,17 +45,6 @@ export const EditorContent = defineComponent({
|
||||
// @ts-ignore
|
||||
editor.contentComponent = instance.ctx._
|
||||
|
||||
if (instance) {
|
||||
editor.appContext = {
|
||||
...instance.appContext,
|
||||
provides: {
|
||||
// @ts-ignore
|
||||
...instance.provides,
|
||||
...instance.appContext.provides,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
editor.setOptions({
|
||||
element,
|
||||
})
|
||||
@ -78,7 +69,6 @@ export const EditorContent = defineComponent({
|
||||
}
|
||||
|
||||
editor.contentComponent = null
|
||||
editor.appContext = null
|
||||
|
||||
if (!editor.options.element.firstChild) {
|
||||
return
|
||||
@ -97,11 +87,35 @@ export const EditorContent = defineComponent({
|
||||
},
|
||||
|
||||
render() {
|
||||
const vueRenderers: any[] = []
|
||||
|
||||
if (this.editor) {
|
||||
this.editor.vueRenderers.forEach(vueRenderer => {
|
||||
const node = h(
|
||||
Teleport,
|
||||
{
|
||||
to: vueRenderer.teleportElement,
|
||||
key: vueRenderer.id,
|
||||
},
|
||||
h(
|
||||
vueRenderer.component as DefineComponent,
|
||||
{
|
||||
ref: vueRenderer.id,
|
||||
...vueRenderer.props,
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
vueRenderers.push(node)
|
||||
})
|
||||
}
|
||||
|
||||
return h(
|
||||
'div',
|
||||
{
|
||||
ref: (el: any) => { this.rootEl = el },
|
||||
},
|
||||
...vueRenderers,
|
||||
)
|
||||
},
|
||||
})
|
||||
|
@ -124,7 +124,7 @@ class VueNodeView extends NodeView<Component, Editor, VueNodeViewRendererOptions
|
||||
}
|
||||
|
||||
get dom() {
|
||||
if (!this.renderer.element || !this.renderer.element.hasAttribute('data-node-view-wrapper')) {
|
||||
if (!this.renderer.element.hasAttribute('data-node-view-wrapper')) {
|
||||
throw Error('Please use the NodeViewWrapper component for your node view.')
|
||||
}
|
||||
|
||||
@ -183,18 +183,14 @@ class VueNodeView extends NodeView<Component, Editor, VueNodeViewRendererOptions
|
||||
this.renderer.updateProps({
|
||||
selected: true,
|
||||
})
|
||||
if (this.renderer.element) {
|
||||
this.renderer.element.classList.add('ProseMirror-selectednode')
|
||||
}
|
||||
this.renderer.element.classList.add('ProseMirror-selectednode')
|
||||
}
|
||||
|
||||
deselectNode() {
|
||||
this.renderer.updateProps({
|
||||
selected: false,
|
||||
})
|
||||
if (this.renderer.element) {
|
||||
this.renderer.element.classList.remove('ProseMirror-selectednode')
|
||||
}
|
||||
this.renderer.element.classList.remove('ProseMirror-selectednode')
|
||||
}
|
||||
|
||||
getDecorationClasses() {
|
||||
|
@ -1,7 +1,5 @@
|
||||
import { Editor } from '@tiptap/core'
|
||||
import {
|
||||
Component, DefineComponent, h, markRaw, reactive, render,
|
||||
} from 'vue'
|
||||
import { Component, markRaw, reactive } from 'vue'
|
||||
|
||||
import { Editor as ExtendedEditor } from './Editor.js'
|
||||
|
||||
@ -10,27 +8,19 @@ export interface VueRendererOptions {
|
||||
props?: Record<string, any>,
|
||||
}
|
||||
|
||||
type ExtendedVNode = ReturnType<typeof h> | null
|
||||
|
||||
interface RenderedComponent {
|
||||
vNode: ExtendedVNode
|
||||
destroy: () => void
|
||||
el: Element | null
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is used to render Vue components inside the editor.
|
||||
*/
|
||||
export class VueRenderer {
|
||||
id: string
|
||||
|
||||
renderedComponent!: RenderedComponent
|
||||
|
||||
editor: ExtendedEditor
|
||||
|
||||
component: Component
|
||||
|
||||
el: Element | null
|
||||
teleportElement: Element
|
||||
|
||||
element: Element
|
||||
|
||||
props: Record<string, any>
|
||||
|
||||
@ -38,40 +28,35 @@ export class VueRenderer {
|
||||
this.id = Math.floor(Math.random() * 0xFFFFFFFF).toString()
|
||||
this.editor = editor as ExtendedEditor
|
||||
this.component = markRaw(component)
|
||||
this.el = document.createElement('div')
|
||||
this.teleportElement = document.createElement('div')
|
||||
this.element = this.teleportElement
|
||||
this.props = reactive(props)
|
||||
this.renderedComponent = this.renderComponent()
|
||||
}
|
||||
this.editor.vueRenderers.set(this.id, this)
|
||||
|
||||
get element(): Element | null {
|
||||
return this.renderedComponent.el
|
||||
}
|
||||
if (this.editor.contentComponent) {
|
||||
this.editor.contentComponent.update()
|
||||
|
||||
renderComponent() {
|
||||
let vNode: ExtendedVNode = h(this.component as DefineComponent, this.props)
|
||||
if (this.teleportElement.children.length !== 1) {
|
||||
throw Error('VueRenderer doesn’t support multiple child elements.')
|
||||
}
|
||||
|
||||
if (typeof document !== 'undefined' && this.el) { render(vNode, this.el) }
|
||||
|
||||
const destroy = () => {
|
||||
if (this.el) { render(null, this.el) }
|
||||
this.el = null
|
||||
vNode = null
|
||||
this.element = this.teleportElement.firstElementChild as Element
|
||||
}
|
||||
}
|
||||
|
||||
return { vNode, destroy, el: this.el ? this.el.firstElementChild : null }
|
||||
get ref(): any {
|
||||
return this.editor.contentComponent?.refs[this.id]
|
||||
}
|
||||
|
||||
updateProps(props: Record<string, any> = {}): void {
|
||||
|
||||
Object
|
||||
.entries(props)
|
||||
.forEach(([key, value]) => {
|
||||
this.props[key] = value
|
||||
})
|
||||
this.renderComponent()
|
||||
}
|
||||
|
||||
destroy(): void {
|
||||
this.renderedComponent.destroy()
|
||||
this.editor.vueRenderers.delete(this.id)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user