1, the preface

WangEditor 5 has been in public beta for a while now, and in the public beta community there are often questions about the official vue component, so I’ve summarized some of the current flaws in @wangEditor /editor-for-vue@next from this perspective:

  • editorId“Allows us to get an example of the editor, which is the end result, but not very efficient or silly to use. It needs to be used after the editor has been destroyededitorIdTo manually clear the cache, which can cause a memory leak if the user forgets this step.
  • Setting content asynchronously requires additional variables to control the creation of the editor, adding complexity to use and not being silly enough
  • defaultContentThe data must be deeply cloned, and the operation is assigned to the user, which increases the complexity
  • Does not supportv-model, push data synchronization to the user, increasing the complexity of use
  • vueIs a framework that supports bidirectional binding, and some of the particular configuration items in our component library are not responsive if the user can passeditable.config.readOnly = falseYou can disable the editor and useeditable.mode = 'simple'You can switch the editor mode, which saves the user n more lines of code and makes it even dumber to use
  • The handling of events can be used directlyconfig.onChange = () => {}I don’t quite understand why I have to mention it alone
  • Special scenario: in a page, there is a list of articles on the left and an editor on the right. If you click an article in the list, the editor will automatically display the content of the article without any historical record (the needs of users in the QQ group before). In this case, the user can only continuously control a variable and assign a value to the variablefalseTo assign a valuetrueTo destroy the rebuild editor if one is available to the userreloadEditorThe API will make it easier to use

On 21/12/21, I started trying to wrap a VUE3 component myself that I thought would work. It will be fully completed by 21/12/30.

This component supports the following functions:

  • Support dynamic configuration of editor parameters (editor created after modification of the configuration items take effect)
  • supportv-modelv-model:htmlTwo forms of bidirectional binding
  • Support dynamic display of default content without a history of old documents
  • The default configuration items are also supportedjson array,json stringhtml stringData in three formats
  • Natural supportTypeScript

For this reason, NPM package is not released at present. If necessary, you can get it from GitHub (only one file). If you think it is useful, you can give it to star.

2. Use of self-contained components

2.1. Global Registration components

import { createApp } from 'vue'
import wangeditor from 'xxx/wangeditor'

// Globally register the EditorToolbar, EditorEditable components
createApp(App).use(wangeditor).mount('#app')
Copy the code

2.2. Start fast

<style lang="scss">
  .border {
    border: 1px solid #ddd;
  }
</style>

<template>
  <editor-toolbar class="border" :option="toolbar" @reloadbefore="onToolbarReloadBefore" />
  <editor-editable
    class="border"
    :option="editable"
    v-model="formData.json"
    v-model:html="formData.html"
    @reloadbefore="onEditableReloadBefore"
  />
</template>

<script lang="ts">
  import { Descendant } from 'slate'
  import {
    EditorEditable,
    EditorEditableOption,
    EditorToolbar,
    EditorToolbarOption,
    useWangEditor,
  } from 'xxx/wangeditor'
  import { defineComponent, shallowReactive } from 'vue'

  export default defineComponent({
    components: { EditorToolbar, EditorEditable },
    setup() {
      // Editor configuration
      const editableOption: EditorEditableOption = {}

      // Menu bar configuration
      const toolbarOption: EditorToolbarOption = {}

      // Buffeting duration. The editor is reloaded 365ms after the configuration item that triggers the reloading changes
      const reloadDelary = 365

      const { editable, toolbar, getEditable, getToolbar, clearContent, reloadEditor } = useWangEditor(
        editableOption,
        toolbarOption,
        reloadDelary
      )

      // Enable read-only mode
      editable.config.readOnly = true

      / / don't use reactive/ref, should use shallowReactive/shallowRef to receive the json data
      const formData = shallowReactive({
        json: [] as Descendant[],
        html: ' ',})function onEditableReloadBefore(inst: IDomEditor) {
        console.log('Editable about to reload:' + new Date().toLocaleString())
      }

      function onToolbarReloadBefore(inst: Toolbar) {
        console.log(The 'Toolbar is about to reload:' + new Date().toLocaleString())
      }

      return { editable, toolbar, formData, onEditableReloadBefore, onToolbarReloadBefore }
    },
  })
</script>
Copy the code

2.3, Vue hook:useWangEditor

After useWangEditor processing, the returned Editable and Toolbar items correspond to the editor and menu bar configuration items, but the configuration item objects are responsive. We can update or reload the editor by directly modifying the editable/ Toolbar corresponding properties.

If editableOption and toolbarOption are passed in as reactive data, they are automatically disassociated internally, meaning that the editable and Toolbar configuration objects that are processed by useWangEditor, Changes in content will not trigger previous dependency updates!!

/** * vue hook, which implements dynamic binding of editor configuration items *@param {Object} Configuration of the body of the editableOption editor *@param {Object} ToolbarOption menu bar configuration *@param {Number} ReloadDelay Delay for controlling the load delay, in milliseconds */
declare function useWangEditor(
  editableOption: EditorEditableOption | null = null,
  toolbarOption: EditorToolbarOption | null = null,
  reloadDelay: number = 365
) :{
  editable: Required<EditorEditableOption>
  toolbar: Required<EditorToolbarOption>
  getEditable: () = > IDomEditor | undefined
  getToolbar: () = > Toolbar | undefined
  clearContent: () = > void
  reloadEditor: () = > void
}
Copy the code

2.3.1 Configuration Items:EditorEditableOption

/** * editor configuration item */
interface EditorEditableOption {
  /** Editor mode */mode? :'default' | 'simple'
  /** The default for editor initialization */defaultContent? : Descendant[] |string | null
  /** Editor configuration, the specific configuration is subject to the official */config? : Partial<IEditorConfig>/** V-model/V-model: HTML data synchronization chattering duration. Default value: 3650, in milliseconds */delay? :number
  /** * The priority of the content when the editor is created. Default: true. * true: V-model > V-model: HTML > defaultContent. * false: defaultContent > V-model > V-model: HTML * /extendCache? :boolean
}
Copy the code

2.3.2 Configuration Items:EditorToolbarOption

/** * Menu bar configuration item */
interfaceEditorToolbarOption { mode? :'default' | 'simple'config? : Partial<IToolbarConfig> }Copy the code

2.4. Dynamically modify the configuration

const { editable, toolbar } = useWangEditor()

editable.config.placeholder = 'new placeholder'

// Switch to read-only mode
editable.config.readOnly = true

toolbar.mode = 'simple'
Copy the code

2.4.1 Data Priority:EditorEditableOption.extendCache

When v-model/v-model: HTML is used in conjunction with defaultContent, we can use extendCache configuration items to control the defaultContent of the overloaded editor.

When extendCahce is true, the priority of the content displayed when the editor is created/reloaded is v-Model > V-Model: HTML > defaultContent.

When extendCache is false, the priority of the content displayed during editor creation/reload is defaultContent > V-Model > V-model: HTML. False mode may cause data loss, so data must be saved before the editor reloads. We can configure the reloadbefore event to save data.

2.4.2 Default Values:EditorEditableOption.defaultContent

DefaultContent changes do not trigger editor reloading by default. If we want to display defaultContent directly, we need to use the reloadEditor to force the editor to reload. And we need to be aware of extendCache’s impact on the default content of the overloaded editor.

const { editable, toolbar, reloadEditor } = useWangEditor()

onMounted(() = > {
  setTimeout(() = > {
    // When you do v-model/ V-model: HTML binding, if you want to reset it after the editor is reloaded
    // Set the default value of extendCache to false.
    // This will result in the loss of editor content, which can be properly handled with the reloadbefore event
    editable.extendCache = false

    // Then modify the configuration
    editable.defaultContent = [{ type: 'header1'.children: [{ text: 'Title one'}}]]String JSON is also supported
    editable.defaultContent = '[{" type ":" header1 ", "children" : [{" text ", "a title"}]}]'

    // It is compatible with HTML strings.
    editable.defaultContent = '

Heading a

Paragraph

'
// Finally, you need to forcibly reload the editor reloadEditor() }, 5000)})Copy the code

2.5. Editor/menu bar reloading

EditorEditableOption mode, EditorEditableOption. Config. HoverbarKeys, EditorEditableOption. Config. MaxLength, EditorEditableO Changes to ption. Config. customPaste trigger reloading of the editor. The other EditorEditableOption options only support dynamic configuration but do not trigger reloading, which avoids unnecessary resource consumption. If you need to force an editor reload, the reloadEditor API is also provided for users to manually trigger.

Unlike EditorEditableOption, any change in EditorToolbarOption triggers a menu bar reload.

const { reloadEditor } = useWangEditor()

// Force the editor to reload
reloadEditor()
Copy the code

2.5.1 Before reloading:reloadbeforeThe event

Before the editor is reloaded, the reloadBefore event is emitted.

<template>
  <editor-toolbar :option="toolbar" @reloadbefore="onToolbarReloadBefore" />
  <editor-editable v-model="formData.json" :option="editable" @reloadbefore="onEditableReloadBefore" />
</template>

<script lang="ts">
  import axios from 'axiios'
  import { Descendant } from 'slate'
  import { EditorEditable, EditorToolbar, useWangEditor } from 'xxx/wangeditor'
  import { defineComponent, shallowReactive } from 'vue'

  export default defineComponent({
    components: { EditorToolbar, EditorEditable },
    setup() {
      const { editable, toolbar, reloadEditor } = useWangEditor()

      const formData = shallowReactive({
        json: [] as Descendant[],
      })

      function onEditableReloadBefore(inst: IDomEditor) {
        window.alert('Editable about to reload')
        console.log('Editable about to reload:' + new Date().toLocaleString())
        // Submit data
        axios.post('xxx/xxx', formData)
      }

      function onToolbarReloadBefore(inst: Toolbar) {
        window.alert('Toolbar about to reload')
        console.log(The 'Toolbar is about to reload:' + new Date().toLocaleString())
      }

      return { editable, toolbar, formData, onEditableReloadBefore, onToolbarReloadBefore }
    },
  })
</script>
Copy the code

2.6. Clear the content

Not only will the editor content be cleared, but v-Model/V-Model: HTML data will also be synchronized

const { clearContent } = useWangEditor()

clearContent()
Copy the code

2.7. Get menu bar instance

const { getToolbar } = useWangEditor()

const toolbarInstance: Toolbar | undefined = getToolbar()
if (toolbarInstance) {
  // do somthing
} else {
  // do somthin
}
Copy the code

2.8. Get the editor instance

const { getEditable } = useWangEditor()

const editableInstance: IDomEditor | undefined = getEditable()
if (editableInstance) {
  console.log(editableInstance.children)
} else {
  console.error('Editor not instantiated')}Copy the code

2.9. Support for V-Model

EditorEditable supports v-Model and V-Model: HTML data binding, corresponding to JSON array and HTML String respectively. Both formats can be bound at the same time, or they can be bound separately to either V-Model or V-Model: HTML, or they can be bound without data binding.

V-model: HTML binding only is not recommended, there are inevitable defects!! And be aware of the possible impact of extendCache!!

At the same time, as we proceedv-modelThis parameter is recommended for bindingshallowReactive/shallowRefTo cachejson arrayThe data. If you insist on usingreactive/refIf you cache data, unknown errors occur at runtime, and you may not find the problem. Important! Important!!!!! Important!!

<template>
  <editor-editable :option="editable" v-model="formData.json" v-model:html="formData.html" />
</template>

<script lang="ts">
  import { Descendant } from 'slate'
  import { useWangEditor } from '@we/wangeditor'
  import { defineComponent, shallowReactive } from 'vue'

  export default defineComponent({
    setup() {
      const { editable } = useWangEditor()

      const formData = shallowReactive({
        json: [] as Descendant[],
        html: ' ',})return { editable, formData }
    },
  })
</script>
Copy the code

or

<template>
  <editor-editable :option="editable" v-model="jsonData" v-model:html="htmlData" />
</template>

<script lang="ts">
  import { Descendant } from 'slate'
  import { useWangEditor } from '@we/wangeditor'
  import { defineComponent, shallowRef } from 'vue'

  export default defineComponent({
    setup() {
      const { editable } = useWangEditor()

      const jsonData = shallowRef<Descendant[]>([])

      const htmlData = ref(' ')

      return { editable, jsonData, htmlData }
    },
  })
</script>
Copy the code

3, summarize

What impressed me most about this package was that it was a responsive API, and that bugs came from responsive apis. So, if you’re also using third-party libraries that use responsive data, Use toRaw, markRaw, shallowReactive, shallowReadonly, unref, and shallowRef apis to remove the responsiveness of data. Otherwise, runtime bugs are not so easy to fix.

The official wangEditor example for addressing runtime bugs caused by reactive features (Issues :262) is a deep clone of the data, which is not elegant, but is exceptionally useful and simple. Of course, in this component, as long as you follow the documentation, you don’t have to worry about it.

4, the last

For this reason, NPM package is not released at present. If necessary, you can get it from GitHub (only one file). If you think it is useful, you can give it to star.