前言
之前公司项目有一个需求是在PC端发布文章,然后会在h5端推送文章,但是公司用到的富文本编辑器居然是UEditor,这款由百度提供的富文本编辑器已经停止维护几年了,个人感觉不好用,而且感觉样式也不太好看,最近新项目的富文本编辑器我果断选择了wangEditor,虽说是个人维护的项目,用起来还是挺顺手的,没有遇到大的问题。
安装
因为项目使用的是Vue3,所以安装的是v5版本
npm install @wangeditor/edito @wangeditor/editor-for-vue@next --save
使用
使用也比较方便,只需要在需要使用的地方Editor, Toolbar
就行,因为使用的地方不止一处,所以这里封装了组件。
<template>
<div style="border: 1px solid #ccc">
<Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" />
<Editor
style="height: 400px; overflow-y: hidden;"
:class="readonly ? 'wang_editor' : ''"
v-model="valueHtml"
:defaultConfig="editorConfig"
:mode="mode"
@onCreated="handleCreated"
@customUpload="onCustomUpload"
@onBlur="handleBlur"
ref="wangeditorRef"
/>
</div>
</template>
<script>
export default {
name: 'WEditor'
}
</script>
<script setup>
import { onBeforeUnmount, ref, shallowRef, onMounted, nextTick, watch } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import '@wangeditor/editor/dist/css/style.css' // 引入 css
const props = defineProps({
htmls: {
type: String,
default: ""
},
value: {
type: String,
default: ""
},
readonly: { // 是否可输入
type: Boolean,
default: false
}
})
const emit = defineEmits(["update:value", 'blur'])
watch(() => props.value, value => {
valueHtml.value = value
})
// 编辑器实例,必须用 shallowRef
const editorRef = shallowRef()
// 内容 HTML
const valueHtml = ref('')
// 配置内容
const mode = ref('simple') // 'default' 或者 'simple'
const toolbarConfig = {
excludeKeys: ['insertVideo', 'insertTable', 'fullScreen', 'undo', 'redo', 'todo'],
}
const editorConfig = {
placeholder: '请输入内容...',
MENU_CONF: {}
}
editorConfig.MENU_CONF['uploadImage'] = {
base64LimitSize: 5 * 1024 * 1024,
}
const handleBlur = () => {
emit('blur')
}
const onCustomUpload = () => {
}
const handleCreated = (editor) => {
editorRef.value = editor // 记录 editor 实例,重要!
if (props.readonly) {
editorRef.value.disable()
}
}
// 组件销毁时,也及时销毁编辑器
onBeforeUnmount(() => {
const editor = editorRef.value
if (editor == null) return
editor.destroy()
})
watch(valueHtml, (n) => {
emit('update:value', n)
})
</script>
这里讲几个比较重要的参数。
1. toolbarConfig工具栏配置
其中toolbarKeys表示工具栏上的菜单按钮,不配置会有一个默认值,可以使用editor.getAllMenuKeys()获取所有的菜单,如果不够可以使用insertKeys:[]属性添加菜单,当然如果觉得多了还可以使用excludeKeys:[]排除不需要的菜单。
const toolbarConfig = {
insertKeys:[],
excludeKeys: ['insertVideo', 'insertTable', 'fullScreen', 'undo', 'redo', 'todo'],
}
2.editorConfig编辑器配置
使用editorCongfig.MENU_CONF[属性名],可以自定义属性值配置,其中我觉得最重要的就是图片上传,这里有一个我觉得非常好用的属性就是可以配置图片小于一个定值时自动转Base64格式,因为这边的后端没有给单独上传图片的接口。这里有一个坑,就是图片如果大于3M左右,转为base64格式后,在PC端显示没有问题,在小程序上会因为过长而无法解析富文本。
const editorConfig = {
placeholder: '请输入内容...',
MENU_CONF: {}
}
editorConfig.MENU_CONF['uploadImage'] = {
base64LimitSize: 5 * 1024 * 1024, // 图片小于5M时自动转Base64格式
}
当然,如果后端有给出单独上传的接口,可以使用自定义上传的配置。
editorConfig.MENU_CONF['uploadImage'] = {
// 自定义上传
async customUpload(file: File, insertFn: InsertFnType) { // TS 语法
// async customUpload(file, insertFn) { // JS 语法
// file 即选中的文件
// 自己实现上传,并得到图片 url alt href
// 最后插入图片
insertFn(url, alt, href)
}
}
小程序富文本回显方法
这里说一下小程序端回显的问题,uni-app
可以直接使用rich-text
回显,但是却有一个问题,如果上传的是PC端比例的大图,在小程序端会把屏幕撑出很长得滚动条,改样式什么完全没有用,必须使用正则替换掉生成的图片上自带的样式,再添加自适应的样式,这里贴出我使用的方法。
const formatRichText = (html) => {
html = html.replaceAll('style=""','')
let newContent = html.replace(/<img[^>]*>/gi, function (match, capture) {
match = match.replace(/style="[^"]+"/gi, '').replace(/style='[^']+'/gi, '');
match = match.replace(/width="[^"]+"/gi, '').replace(/width='[^']+'/gi, '');
match = match.replace(/height="[^"]+"/gi, '').replace(/height='[^']+'/gi, '');
return match;
});
newContent = newContent.replace(/style="[^"]+"/gi, function (match, capture) {
match = match.replace(/width:[^;]+;/gi, 'max-width:100%;').replace(/width:[^;]+;/gi, 'max-width:100%;');
return match;
});
newContent = newContent.replace(/<br[^>]*/>/gi, '');
newContent = newContent.replace(/<img/gi, '<img style="max-width:100%;height:auto;display:block;margin:10px 0;"');
return newContent;
}
最后在哪里需要使用就可以用组件的形式直接引用了。