当前文档是 wangEditor v4 版本的。
wangEditor v5 已经正式发布,可参考文档。
v5 发布之后,v4 将不再开发新功能。
English documentation
wangEditor4 —— 轻量级 web 富文本编辑器,配置方便,使用简单。
wangeditor
wangeditor v4 npm i wangeditor --save
基本使用:
欢迎使用 wangEditor 富文本编辑器
wangeditor
import E from 'wangeditor'
根据 ref 设置 编辑器元素高度,实例化 wangeditor
const editorRef = ref()
editor = new E(editorRef.value)
默认情况下,显示所有菜单
// 配置菜单栏,删减菜单,调整顺序
editor.config.menus = [
'bold',
'head',
'link',
'italic',
'underline'
]
editor.config.uploadImgMaxLength = 3
editor.config.uploadImgMaxSize: 10 * 1024 * 1024, // 10M
uploadImgServer: props.action, // 配置 server 接口地址
uploadImgHeaders: {
Authorization: `Bearer ${getPiniaToken()}`,
'X-Requested-With': 'XMLHttpRequest',
},
editor.config.customUploadImg = function (resultFiles, insertImgFn) {
// resultFiles 是 input 中选中的文件列表
// insertImgFn 是获取图片 url 后,插入到编辑器的方法
// 上传图片,返回结果,将图片插入到编辑器中
insertImgFn(imgUrl)
}
editor.config.uploadImgHooks = {
// 上传图片之前
before: function(xhr) {
console.log(xhr)
// 可阻止图片上传
return {
prevent: true,
msg: '需要提示给用户的错误信息'
}
},
// 图片上传并返回了结果,图片插入已成功
success: function(xhr) {
console.log('success', xhr)
},
// 图片上传并返回了结果,但图片插入时出错了
fail: function(xhr, editor, resData) {
console.log('fail', resData)
},
// 上传图片出错,一般为 http 请求的错误
error: function(xhr, editor, resData) {
console.log('error', xhr, resData)
},
// 上传图片超时
timeout: function(xhr) {
console.log('timeout')
},
// 图片上传并返回了结果,想要自己把图片插入到编辑器中
// 例如服务器端返回的不是 { errno: 0, data: [...] } 这种格式,可使用 customInsert
customInsert: function(insertImgFn, result) {
// result 即服务端返回的接口
console.log('customInsert', result)
// insertImgFn 可把图片插入到编辑器,传入图片 src ,执行函数即可
insertImgFn(result.data[0])
}
}
如果使用了 customUploadImg
自定义上传事件,那么 wangeditor
其他的图片上传api将会失效,例如: uploadImgServer
和 uploadImgHeaders
,uploadImgHooks
以上都是修改在 editor.config
,可以直接在 定义一个对象在editor.config
中,看自己的需求:
wangeditor 4 不支持源码模式,但可以自定义新增菜单
在 wangeditor
中创建 dom,按照官方文档写法如下:
constructor(editor: E) {
// data-title属性表示当鼠标悬停在该按钮上时提示该按钮的功能简述
const $elem = $(`
`)
super($elem, editor)
}
给新增的dom菜单添加事件
// 菜单点击事件
clickHandler() {
this.switchMode()
this.tryChangeActive()
}
修改源码模式
enum Mode {
// 源码模式
Source = 'source',
// 实时预览模式
Live = 'live',
}
上面使用了枚举定义,也可以不需要做,看自己的使用方式
在这里判断模式状态
this.mode = this.isSouceMode() ? Mode.Live : Mode.Source
重新设置编辑器内容
let html = this.editor.txt.html() || ''
切换为源码模式,替换内容
使用字符串replace()
函数查找字符进行转换,输出为源码Html
html = html.replace(//g, '>').replace(/ /g, ' ')
源码转换为文本内容
html = this.editor.txt
.text()
.replace(/</gi, '<')
.replace(/>/gi, '>')
.replace(/ /gi, ' ')
菜单激活事件,每次切换菜单的时候要调用下wangeditor 方法,否则编辑器不知道你当前菜单(扩展)有哪些
tryChangeActive() {
if (this.isSouceMode()) {
this.active()
} else {
this.unActive()
}
}
其他,扩展菜单可以参考文档案例:https://codepen.io/xiaokyo-the-bold/pen/ZEpWBeo
扩展菜单class
export default class sourceMenu extends BtnMenu {
mode = Mode.Live
constructor(editor: E) {
const $elem = $(`
`)
super($elem, editor)
}
// 菜单点击事件
clickHandler() {
this.switchMode()
this.tryChangeActive()
}
tryChangeActive() {
if (this.isSouceMode()) {
this.active()
} else {
this.unActive()
}
}
isSouceMode() {
return this.mode === Mode.Source
}
switchMode() {
this.mode = this.isSouceMode() ? Mode.Live : Mode.Source
let html = this.editor.txt.html() || ''
if (this.isSouceMode()) {
html = html.replace(//g, '>').replace(/ /g, ' ')
} else :
html = this.editor.txt
.text()
.replace(/</gi, '<')
.replace(/>/gi, '>')
.replace(/ /gi, ' ')
}
this.editor.txt.html(html)
}
}
在页面加载时,初始化wangeditor配置
editor.create()
editor.txt.html(props.modelValue) // 初始化重新设置编辑器内容
部分代码
onMounted(() => {
editor = new E(editorRef.value)
// 扩展自定义【源码】菜单
const sourceMenuKey = 'source'
editor.menus.extend(sourceMenuKey, sourceMenu)
// 配置
Object.assign(editor.config, {
zIndex: 1,
focus: false,
height: props.height,
menus: [
sourceMenuKey, // 源码菜单
'head',
'bold',
'fontSize',
'fontName',
'italic',
'underline',
'strikeThrough',
'indent',
'lineHeight',
'foreColor',
'backColor',
'link',
'list',
'todo',
'justify',
'quote',
'emoticon',
'image',
// 'video', // 移除视频菜单
'table',
'code',
'splitLine',
'undo',
'redo',
],
uploadFileName: 'file',
uploadImgParams: {
path: props.path,
},
uploadImgServer: '', // 配置 server 接口地址
uploadImgHeaders: {
Authorization: 'token',
'X-Requested-With': 'XMLHttpRequest',
},
// 限制上传的最大图片数量
uploadImgMaxLength: 2,
// 单个文件的最大体积限制,默认为 10M
uploadImgMaxSize: 5 * 1024 * 1024, // 5M
customUploadImg: (files: Blob[], insertImgFn: (path: string) => void) => {
try {
const imgData = new FormData()
for (let i in files) {
imgData.append(`file`, files[i])
}
// 请求接口,并通过 insertImgFn()函数 插入到编辑器中
// imgUrl 是从接口返回的图片地址
insertImgFn(imgUrl)
} catch (error) {
message.error('图片上传失败,请重新上传')
}
},
uploadImgHooks: {
customInsert: function (insertImgFn: (path: string) => void, res: Recordable) {
// res即远程请求的response
// insertImgFn 可把图片插入到编辑器,传入图片 src ,执行函数即可
insertImgFn(res.data.path as string)
},
},
onchange() {
let sourceMenu = editor?.menus.menuList.find((item) => item.key === sourceMenuKey)
emit('update:isActive', sourceMenu?.isActive)
emit('update:modelValue', editor!.txt.html())
},
onblur() {
lock = true
},
})
editor.create()
editor.txt.html(‘回显时的内容’) // 初始化重新设置编辑器内容
watchEffect(() => {
props.disabled ? editor?.disable() : editor?.enable()
})
})
onBeforeUnmount(() => {
editor!.destroy()
editor = null
})