在 vue 中使用 wangEditor v5

11,868 阅读3分钟

一、前言

wangEditor 是一个快速接入,配置简单,几行代码即可生成。集成了所有常见功能,无需二次开发的富文本编辑器。它的下一个版本(v5)预计在4月份发布正式版。v5 提供了官方的 vue/react 组件库,不过从一个使用者的角度来说,使用起来不是很方便。

二、wangeditor5-for-vue2

image.png

1、功能亮点

  • 动态配置

    符合 Vue 使用习惯,数据驱动,通过修改配置即可更新编辑器(编辑器创建后修改配置项仍生效)

  • 双向绑定

    支持 v-bind:jsonv-bind:html 两种形式的双向绑定,分别对应 json stringhtml string 两种形式的数据

  • 初始内容

    编辑器创建时的默认内容配置项支持 json arrayjson stringhtml string 三种格式的数据

  • 优雅切换

    defaultContent/defaultHtml + reloadEditor() 可优雅的实现在不同文章间的来回切换

  • Vetur

    提供 Vetur 语法提示和自动完成所需的配置文件

2、快速开始

@wangeditor/editor 的版本建议在 0.14.0 及以上,因为 0.14.0 以下的版本不支持 defaultHtml 选项配置。

2.1、安装

yarn add @wangeditor/editor wangeditor5-for-vue2
// or
npm install @wangeditor/editor wangeditor5-for-vue2

2.2、示例

2.2.1、WeToolbar + WeEditable

wangeditor5-for-vue2 组件库中,菜单栏和编辑区分别提供了独立的组件,可供使用者在特殊场景下使用。

<template>
  <div>
    <we-toolbar :option="toolbar" />
    <we-editable
      :option="editable"
      :json.sync="data.json"
      :html.sync="data.html"
    />
  </div>
</template>

<script>
  import { useWangEditor } from 'wangeditor5-for-vue2'
  export default {
    data() {
      const { toolbar, editable } = useWangEditor({
        config: {
          placeholder: 'WeToolbar + WeEditable 示例'
        },
        onCreated: (inst) => {
          console.log(inst)
          // 使用了箭头函数,因此 this 指向当前组件实例
          console.log(this.editable.config.placeholder)
        },
      })

      return {
        toolbar,
        editable,
        data: {
          json: '',
          html: '',
        },
      }
    },
  }
</script>

2.2.2、WeEditor

WeEditor 组件将 WeToolbarWeEditable 组件封装在了一个组件中,使用更方便。

<template>
  <we-editor
    :toolbar-option="toolbar"
    :editable-option="editable"
    :json.sync="data.json"
    :html.sync="data.html"
  />
</template>

<script>
  import { useWangEditor } from 'wangeditor5-for-vue2'
  export default {
    data() {
      return {
        data: {
          json: '',
          html: '',
        },
        ...useWangEditor({
          config: {
            placeholder: 'WeEditor 示例'
          },
        }),
      }
    },
  }
</script>

3、Vetur 配置

通过简单配置,即可让 Vetur 支持本组件库相关组件的语法提示和自动完成功能。

3.1、快速使用

package.json 文件中进行如下配置,然后重启 vscode 即可。

{
  "vetur": {
    "tags": "wangeditor5-for-vue2/vetur/tags.json",
    "attributes": "wangeditor5-for-vue2/vetur/attributes.json"
  }
}

3.2、更多

如果你还有其它自定义的 Vetur 配置文件,你可以直接将 node_modules/wangeditor5-for-vue2/vetur 下的文件与你自己的文件内容进行手动合并即可。

三、wangeditor5-for-vue3

wangeditor5-for-vue3wangeditor5-for-vue2 的兄长,wangeditor5-for-vue2 的实现思路几乎与 wangeditor5-for-vue3 一样。wangeditor5-for-vue2 在功能上算是 wangeditor5-for-vue3 阉割版,wangeditor5-for-vue3 功能更强大。

@wangeditor/editor 的版本建议在 0.14.0 及以上,因为 0.14.0 以下的版本不支持 defaultHtml 选项配置。

image.png

1、安装

yarn add @wangeditor/editor wangeditor5-for-vue3
// or
npm install @wangeditor/editor wangeditor5-for-vue3

2、使用示例

2.1、WeToolbar + WeEditable

<template>
  <we-toolbar :option="toolbar" />
  <we-editable
    :option="editable"
    v-model="formData.jarr"
    v-model:json="formData.jstr"
    v-model:html="formData.html"
  />
</template>

<script lang="ts">
  import { SlateDescendant } from '@wangeditor/editor'
  import { WeEditable, WeToolbar, useWangEditor } from 'wangeditor5-for-vue3'
  import { defineComponent, shallowReactive } from 'vue'
  // 引入 wangeditor5 样式
  import '@wangeditor/editor/dist/css/style.css'

  export default defineComponent({
    components: { WeToolbar, WeEditable },
    setup() {

      const { editable, toolbar } = useWangEditor()

      // 不要使用 reactive/ref,应该使用 shallowReactive/shallowRef 来接收 json array 数据
      const formData = shallowReactive({
        jarr: [] as SlateDescendant[], 
        jstr: '', 
        html: '' 
      })

      return { editable, toolbar, formData }
    },
  })
</script>

2.2、WeEditor

<template>
  <we-editor
    :toolbar-option="toolbar"
    :editable-option="editable"
    v-model="ruleForm.jarr"
    v-model:json="formData.jstr"
    v-model:html="formData.html"
  />
</template>

<script lang="ts">
  import { WeEditor, useWangEditor } from 'wangeditor5-for-vue3'
  import { defineComponent, shallowReactive } from 'vue'
  import { SlateDescendant } from '@wangeditor/editor'
  // 引入 wangeditor5 样式
  import '@wangeditor/editor/dist/css/style.css'

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

      const formData = shallowReactive({ 
        jarr: [] as SlateDescendant[], 
        jstr: '', 
        html: '' 
      })

      return { editable, toolbar, formData }
    },
  })
</script>

2.3、WeEditorPlus

WeEditorPlus 组件意在解决全局样式污染的问题,让你在使用时不会因全局样式而出现不合预期的状况,其底层基于浏览器原生的 Web ComponentShadow Dom

虽然实现了样式的隔绝,但是它的兼容性略差:WeEditorPlus 组件在 Firefox 浏览器和 vue-cli 项目中无法正常使用。

<template>
  <we-editor-plus
    :toolbar-option="toolbar"
    :editable-option="editable"
  />
</template>

<script lang="ts">
  import { WeEditorPlus, useWangEditor } from 'wangeditor5-for-vue3'
  import { defineComponent } from 'vue'

  export default defineComponent({
    components: { WeEditorPlus },
    setup() {
      // useWangEditor() 的使用和常规模式下的使用时一样的
      const { editable, toolbar } = useWangEditor()

      return { editable, toolbar }
    },
  })
</script>

3、表单验证

wangeditor5-for-vue3 的组件支持在其它 UI 框架的表单中使用,同时支持 blurchange 两种 trigger 模式。

3.1、目前已支持的 UI 框架

3.2、表单验证定义规则

3.2.1、定义表单验证初始化函数

import { WeEditorFormFields } from 'wangeditor5-for-vue3'

function weFormFields() {
  const formFields: WeEditorFormFields = {}

  formFileds.blurField = () => {
    // trigger: blur 的具体逻辑
  }
  formFileds.changeField = () => {
    // trigger: change 的具体逻辑
  }

  return formFields
}
interface WeEditorFormFields {
  blurField?: () => void
  changeField?: () => void
}

3.2.2、注入表单验证初始化函数

3.2.2.1、全局挂载
import { createApp } from 'vue'

const app = createApp(App)

app.config.globalProperties.$weFormFields = weFormFields

app.mount('#app')
3.2.2.2、provide
import { defineComponent, provide } from 'vue'
import { weFormFieldInjectionKey } from 'wangeditor5-for-vue3'

export default defineComponent({
  components: { UPrism },
  setup() {
    provide(weFormFieldInjectionKey, weFormFields)

    return {}
  },
})

四、结尾

vue 的响应式特性能给我们带来很多便利,但是在 vue 中使用其它 包/库 的时候,一定要注意响应式特性可能会造成一些意外情况,尽量规避它。