vue3 uses the rich text editor wangEditor 5 to add a custom drop-down box and dynamically change the content of the drop-down box

Write a custom directory title here

    • official information
    • Show results
    • Preparation
      • Install
      • use
      • demo
      • Custom extension function (drop-down box)
        • First, define the menu class
        • Second, register the menu to wangEditor
        • Third, insert the menu into the toolbar
    • final code
      • selectTest.ts
      • editorDemo.vue

Official information

  • wangEditor official website

Effect display

20231101-150658.gif

Preparation

Just follow the Vue3 Demo operation provided by wangEditor official website here. You can skip the following content directly.

Installation

yarn add @wangeditor/editor
# Or npm install @wangeditor/editor --save

yarn add @wangeditor/editor-for-vue@next
# Or npm install @wangeditor/editor-for-vue@next --save

Use

stencil

<template>
    <div style="border: 1px solid #ccc">
      <Toolbar
        style="border-bottom: 1px solid #ccc"
        :editor="editorRef"
        :defaultConfig="toolbarConfig"
        :mode="mode"
      />
      <Editor
        style="height: 500px; overflow-y: hidden;"
        v-model="valueHtml"
        :defaultConfig="editorConfig"
        :mode="mode"
        @onCreated="handleCreated"
      />
    </div>
</template>

script

<script>
import '@wangeditor/editor/dist/css/style.css' // Import css

import {<!-- --> onBeforeUnmount, ref, shallowRef, onMounted } from 'vue'
import {<!-- --> Editor, Toolbar } from '@wangeditor/editor-for-vue'

export default {<!-- -->
  components: {<!-- --> Editor, Toolbar },
  setup() {<!-- -->
    //Editor instance, shallowRef must be used
    const editorRef = shallowRef()

    // Content HTML
    const valueHtml = ref('<p>hello</p>')

    // Simulate ajax to asynchronously obtain content
    onMounted(() => {<!-- -->
        setTimeout(() => {<!-- -->
            valueHtml.value = '<p>Simulate Ajax asynchronously setting content</p>'
        }, 1500)
    })

    const toolbarConfig = {<!-- -->}
    const editorConfig = {<!-- --> placeholder: 'Please enter content...' }

    //When the component is destroyed, the editor is also destroyed in time.
    onBeforeUnmount(() => {<!-- -->
        const editor = editorRef.value
        if (editor == null) return
        editor.destroy()
    })

    const handleCreated = (editor) => {<!-- -->
      editorRef.value = editor //Record editor instance, important!
    }

    return {<!-- -->
      editorRef,
      valueHtml,
      mode: 'default', // or 'simple'
      toolbarConfig,
      editorConfig,
      handleCreated
    };
  }
}
</script>

demo

At this point we have a default rich text editor
image.png

Custom extension function (drop-down box)

Mainly refer to the SelectMenu documentation provided on the official website

First, define the menu class
import {<!-- --> IDomEditor, ISelectMenu } from '@wangeditor/editor'

class MySelectMenu implements ISelectMenu {<!-- -->
  // Built-in fields
  title: string
  tag: string
  width:number
  //custom fields
  defineTitle: object //The name displayed in the drop-down box
  dataName: string //The drop-down box option value corresponds to the field name in the editor instance, and the value is set through editor[dataName]=[]
  options: any
  //When using the class, you need to accept a parameter dataName
  constructor(dataName: any) {<!-- -->
    this.title = 'select'
    this.tag = 'select'
    this.width = 60
    this.dataName = dataName
    this.defineTitle = {<!-- -->
      value: 'title',
      text: 'Insert field',
      styleForRenderMenuList: {<!-- --> display: 'none' }
    }
  }
  //Options for the drop-down box
  getOptions(editor) {<!-- -->
    //Here I store the value of the drop-down box option in the editor instance so that the option value can be dynamically changed.
    const displayOptions = editor[this.dataName].data || []
    this.options = [this.defineTitle, ...displayOptions]
    return this.options
  }
  // Whether the menu needs to be activated (if bold text is selected, the "bold" menu will be activated), if not used, return false
  isActive(editor: IDomEditor): boolean {<!-- -->
    return false
  }
  // Get the value when the menu is executed. If it is not used, it will return an empty string or false.
  getValue(editor: IDomEditor): string | boolean {<!-- -->
    return 'title' // In order not to change the title of the drop-down box, always return 'title'
  }
  // Whether the menu needs to be disabled (if H1 is selected, the "Reference" menu is disabled), return false if it is not used
  isDisabled(editor: IDomEditor): boolean {<!-- -->
    return false
  }
  // Function triggered when the menu is clicked
  exec(editor: IDomEditor, value: string | boolean) {<!-- -->
    //Insert selected items into rich text
    editor.insertText(`value`)
  }
}
Second, register the menu to wangEditor

Refer to the registration menu in the official website documentation to wangEditor

First define the menu configuration according to the menu class

const menu1Conf = {<!-- -->
  key: 'mySelect1', // Define menu key: ensure uniqueness and non-duplication (important)
  factory() {<!-- -->
    return new MySelectMenu() //This is the class we defined above
  },
}

Then, register the menu to wangEditor.

import {<!-- --> Boot } from '@wangeditor/editor'

Boot.registerMenu(menu1Conf)
Third, insert the menu into the toolbar

Refer to the official website documentation for inserting menus into toolbars.

However, I configured it during initialization and did not insert it additionally. You can configure the menu you want in toolbarConfig.

const toolbarConfig = {<!-- -->
      toolbarKeys: [
        'fontSize',
        'lineHeight',
        '|',
        'bold',
        'italic',
        'underline',
        'color',
        '|',
        '|',
        'justifyLeft',
        'justifyCenter',
        'justifyRight',
        '|',
        'indent',
        'delIndent',
        'mySelect1' //Your own extended drop-down box, but please note that you must register before you can write
      ]
    }

Final code

Here, a new selectTest.ts file is created for the MySelectMenu class defined by myself, and the rest is stuffed into the editorDemo.vue file. Since I only added a custom configuration, many places were written to death…

selectTest.ts

import {<!-- --> IDomEditor, ISelectMenu } from '@wangeditor/editor'

class MySelectMenu implements ISelectMenu {<!-- -->
  // Built-in fields
  title: string
  tag: string
  width:number
  //custom fields
  defineTitle: object
  dataName: string //The drop-down box option value corresponds to the field name in the editor instance, and the value is set through editor[dataName]=[]
  options: any
  constructor(dataName: any) {<!-- -->
    this.title = 'select'
    this.tag = 'select'
    this.width = 60
    this.dataName = dataName
    this.defineTitle = {<!-- -->
      value: 'title',
      text: 'Insert field',
      styleForRenderMenuList: {<!-- --> display: 'none' }
    }
  }
  //Options for the drop-down box
    getOptions(editor: any) {<!-- -->
    //Here I store the value of the drop-down box option in the editor instance so that the option value can be dynamically changed.
    const displayOptions = editor[this.dataName].data || []
    this.options = [this.defineTitle, ...displayOptions]
    return this.options // What is returned here is the value displayed on the drop-down box options
  }
  // Whether the menu needs to be activated (if bold text is selected, the "bold" menu will be activated), if not used, return false
  isActive(editor: IDomEditor): boolean {<!-- -->
    return false
  }
  // Get the value when the menu is executed. If it is not used, it will return an empty string or false.
  getValue(editor: IDomEditor): string | boolean {<!-- -->
    return 'title' // In order not to change the title of the drop-down box, always return 'title'
  }
  // Whether the menu needs to be disabled (if H1 is selected, the "Reference" menu is disabled), return false if it is not used
  isDisabled(editor: IDomEditor): boolean {<!-- -->
    return false
  }
  // Function triggered when the menu is clicked
  exec(editor: IDomEditor, value: string | boolean) {<!-- -->
    //Insert selected items into rich text
    editor.insertText(`${<!-- -->value}`)
  }
}

export default MySelectMenu

editorDemo.vue

<template>
  <div class="editorDemo">
    <div style="border: 1px solid #ccc; width: 800px">
      <Toolbar
        style="border-bottom: 1px solid #ccc"
        :editor="editorRef"
        :defaultConfig="toolbarConfig"
        :mode="mode"
      />
      <Editor
        style="height: 400px; overflow-y: hidden"
        v-model="valueHtml"
        :defaultConfig="editorConfig"
        :mode="mode"
        @onCreated="handleCreated"
      />
    </div>
  </div>

  <a-space wrap style="margin-top: 20px">
    <a-button type="primary" @click="updateSelectOptionData(0)">Click me</a-button>
    <a-button type="primary" @click="updateSelectOptionData(1)"
      >Click me! </a-button
    >
    <a-button type="primary" @click="updateSelectOptionData(2)"
      >Click me! </a-button
    >
  </a-space>
</template>

<script>
import "@wangeditor/editor/dist/css/style.css"; // Import css
import {<!-- --> onBeforeUnmount, ref, shallowRef, onMounted } from "vue";
import {<!-- --> Editor, Toolbar } from "@wangeditor/editor-for-vue";
import {<!-- --> Boot } from "@wangeditor/editor";
import MySelectMenu from "@/editor/selectTest";

export default {<!-- -->
  components: {<!-- --> Editor, Toolbar },
  setup() {<!-- -->
    //Editor instance, shallowRef must be used
    const editorRef = shallowRef();

    // Content HTML
    const valueHtml = ref("");

    //--------Register a custom extension menu, because there is only one, I just wrote it to death---------------
    const selectOption = ref({<!-- -->
      key: "mySelect1",
      dataName: "selectData",
      data: [
        {<!-- --> value: "Beijing", text: "Beijing" },
        {<!-- --> value: "Shanghai", text: "Shanghai" },
        {<!-- --> value: "Shenzhen", text: "Shenzhen" },
      ],
    });
    const menu1Conf = {<!-- -->
      key: selectOption.value.key, // Define menu key: ensure uniqueness and non-duplication (important)
      factory() {<!-- -->
        return new MySelectMenu(selectOption.value.dataName);
      },
    };
    Boot.registerMenu(menu1Conf);
    //------------------------------------------------ ----------------

    //Customize the menu configuration of the toolbar
    const toolbarConfig = {<!-- -->
      toolbarKeys: [
        "fontSize",
        "lineHeight",
        "|",
        "bold",
        "italic",
        "underline",
        "color",
        "|",
        "|",
        "justifyLeft",
        "justifyCenter",
        "justifyRight",
        "|",
        "indent",
        "delIndent",
        "mySelect1",
      ],
    };
    const editorConfig = {<!-- --> placeholder: "Please enter content..." };

    //When the component is destroyed, the editor is also destroyed in time.
    onBeforeUnmount(() => {<!-- -->
      const editor = editorRef.value;
      if (editor == null) return;
      editor.destroy();
    });

    const handleCreated = (editor) => {<!-- -->
      editorRef.value = editor; // Record editor instance, important!
      // I saved the value of the drop-down box option in the editor instance
      editorRef.value[selectOption.value.dataName] = {<!-- -->
        data: selectOption.value.data,
      };
    };

    const dataTest = [
      [
        {<!-- --> value: "Beijing", text: "Beijing" },
        {<!-- --> value: "Shanghai", text: "Shanghai" },
        {<!-- --> value: "Shenzhen", text: "Shenzhen" },
      ],
      [
        {<!-- --> value: "car", text: "car" },
        {<!-- --> value: "big car", text: "big car" },
        {<!-- --> value: "Super Big Car", text: "Super Big Car" },
      ],
      [
        {<!-- --> value: "train", text: "train" },
        {<!-- --> value: "Shanghai", text: "Shanghai" },
        {<!-- --> value: "plane", text: "plane" },
      ],
    ];

    const updateSelectOptionData = (index) => {<!-- -->
      selectOption.value.data = dataTest[index];
      if (editorRef.value == null) return;
      // Mainly to update the value stored in the instance
      editorRef.value[selectOption.value.dataName] = {<!-- -->
        data: selectOption.value.data,
      };
    };

    return {<!-- -->
      editorRef,
      valueHtml,
      mode: "default", // or 'simple'
      toolbarConfig,
      editorConfig,
      handleCreated,
      updateSelectOptionData,
    };
  },
};
</script>
<style scoped>
.editorDemo {<!-- -->
  display: flex;
  justify-content: center;
  align-items: center;
}
</style>