# wangEditor

向军大叔每晚八点在 抖音 (opens new window)bilibli (opens new window) 直播

xj-small

wangEditor (opens new window)是优秀的国产富文本编辑器,下面我们来掌握在项目中集成上这款编辑器。

image-20201120231553289

# 安装

可以使用 npm 或 yarn 进行安装

yarn add wangeditor

也可以使用 cdn 引入,这会减少打包的文件大小

<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/wangeditor@latest/dist/wangEditor.min.js"></script>

# 组件定义

下面分别介绍 wangEditor 组件的两种定义式式。

# TypeScript

然后定义 wangEditorr 的 Vue 组件

<script lang="ts" setup>
import '@wangeditor/editor/dist/css/style.css'
import { onBeforeUnmount, ref, shallowRef, watch } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { IEditorConfig, IDomEditor, IToolbarConfig, createToolbar, DomEditor } from '@wangeditor/editor'

interface IProps {
  modelValue?: any
}
const props = withDefaults(defineProps<IProps>(), {
  modelValue: '',
})

const emit = defineEmits(['update:modelValue'])

// 编辑器实例,必须用 shallowRef
const editorRef = shallowRef<IDomEditor>()

// 内容 HTML
const valueHtml = ref(props.modelValue)

// 组件销毁时,也及时销毁编辑器
onBeforeUnmount(() => {
  const editor = editorRef.value
  if (editor == null) return
  editor.destroy()
})

const handleCreated = (editor: IDomEditor) => {
  editorRef.value = editor
}

watch([valueHtml], (value: any) => {
  emit('update:modelValue', editorRef.value?.getHtml())
})

// 创建工具栏
const mode = ref('default')

const toolbarConfig: Partial<IToolbarConfig> = {
  excludeKeys: ['group-video', 'undo', 'redo'],
}

const editorConfig: Partial<IEditorConfig> = {
  MENU_CONF: {
    uploadImage: {
      server: '/api/upload/image',
    },
  },
}
</script>

<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>

<style lang="scss" scoped>
.w-e-full-screen-container {
  z-index: 9999;
}
</style>

# CDN

有时为了节省打包大小,我们使用CDN方式操作。首先在 vue 模板 index.html中引入静态资源。

<link href="https://unpkg.com/@wangeditor/editor@latest/dist/css/style.css" rel="stylesheet" />
<script src="https://unpkg.com/@wangeditor/editor@latest/dist/index.js"></script>
<script>
  var E = window.wangEditor // 全局变量
</script>

然后声明 wangEditor 组件内容如下

<script lang="ts" setup>
import { uploadImage } from '@@/apis/upload'
const { modelValue, height = '300px' } = defineProps<{ modelValue: string; height?: string }>()
const emit = defineEmits(['update:modelValue'])

const editorConfig: Partial<any> = {
  MENU_CONF: {
    uploadImage: {
      async customUpload(file: File, insertFn: any) {
        const form = new FormData()
        form.append('file', file, file.name)
        const response = await uploadImage(form)
        insertFn(response.data.url, '', '')
      },
    },
  },
  onChange: (editor: any) => {
    console.log('html', editor.getHtml())
    emit('update:modelValue', editor.getHtml())
  },
}
// 工具栏配置
const toolbarConfig: Partial<any> = {}
const win = window as any

nextTick(() => {
  // 创建编辑器
  const editor = win.wangEditor.createEditor({
    selector: '#editor-container',
    config: editorConfig,
    mode: 'default',
  })
  editor.setHtml(modelValue)
  // 创建工具栏
  const toolbar = win.wangEditor.createToolbar({
    editor,
    selector: '#toolbar-container',
    config: toolbarConfig,
    mode: 'default',
  })
})
</script>

<template>
  <div style="border: 1px solid #ccc">
    <div id="toolbar-container" class="border-b"></div>
    <div id="editor-container" :style="{ height }"></div>
  </div>
</template>

<style lang="scss" scoped>
.w-e-full-screen-container {
  z-index: 9999;
}
</style>

# 使用组件

<script setup lang="ts">
import Editor from '@/components/wang/editor.vue'
import { ref } from 'vue';
const content = ref('abc')
</script>

<template>
	<div class>
		<Editor :config="{ height: 300 }" v-model="content" />
		{{ content }}
	</div>
</template>

下面对 props 属性进行说明

属性 说明 默认值
v-model 编辑器数据
height 编辑器高度

# 图片上传

下面对图片上传的前后端进行说明。

前台

上面组件上传使用了 @@/apis/upload是用axios封装的。这样可以让上传像其他api一样统一处理,比如使用token。

你自行参数 axios 文档封装就可以了

后台

后台需要返回以下数据结构

data: { url: '图片地址' }