前言
半路接手的后台项目,里面的富文本编辑器使用的kindeditor,总感觉有些臃肿,而且之前的人在封装组件后,使用起来有些bug,于是从网上搜了一下,决定使用wangeditor进行重新封装,这里将使用笔记留下,供以后查看,并分享。
1.基本使用
这个没什么好说的了,去官网看文档就好了。
出现的几个小问题:
- 注意设置一下editor的z-index(
editor.config.zIndex
),因为他的默认z-index很大,很有可能遮挡住你的其他控件(如弹窗等)。 - 使用接口获取已经保存的富文本内容,并将内容
v-bind
到editor组件的时候,由于请求数据需要时间,很大可能造成富文本框组件渲染时props
还没获取到富文本内容,无法在mounted
事件中直接将内容回填到富文本框,这里我直接在editor组件中通过watch
解决的。
2.图片上传
如果需要自己实现上传逻辑,可参考并配置editor.config.customUploadImg
。
我的情况是,我们有自己的图片上传组件,希望使用自己的组件进行上传,这时需要配置editor.config.uploadImgFromMedia
方法,替换本地上传功能,在其中加入自己的逻辑。
记着上传结束后调用editor.cmd.do
方法将图片插入富文本内容中。
3.视频上传
同上,我们也希望使用自己的组件替换原始的本地上传,可是文档中没有提供类似editor.config.uploadImgFromMedia
的方法。
没办法,只能使用自定义扩展Button菜单的方式完成了。
思路如下:
- 配置中删除video菜单。
- 加入自定义扩展Button菜单。
- 增加配置一个
editor.config.uploadVideoFromMedia
函数,来实现我们自己的逻辑。
在自定义扩展Button菜单的类中:
- 自定义菜单沿用之前video菜单的样式,保证样式一致。
- 在自定义菜单中,设置菜单点击事件去调用我们自己配置的
editor.config.uploadVideoFromMedia
。
这样,实现了视频上传中类似editor.config.uploadImgFromMedia
的方法。
自定义扩展Button菜单的类的代码如下:
//wangeditor的自定义视频上传菜单
import E from 'wangeditor';
const BtnMenu = E.BtnMenu;
class NewVideoMenu extends BtnMenu{
constructor(editor){
const $elem = E.$(
`<div class="w-e-menu" data-title="视频">
<i class="w-e-icon-play"></i>
</div>`
);
super($elem, editor);
}
clickHandler(){
this.editor.config.uploadVideoFromMedia();
}
tryChangeActive(){}
}
export default NewVideoMenu;
通过控制自定义菜单在editor的配置数组editor.config.menus
中的插入位置,来调整菜单的显示位置。
4.上传的视频在富文本框没有光标、无法删除的问题
视频上传结束时:
let videoHTML = ' <video src="' + this.video_url + '" controls style="max-width:100%"></video> ';
this.editor.cmd.do('insertHTML', videoHTML);
视频标签的两侧各加一个空格的转义字符
,可以使光标在富文本的视频周围出现,并可以删除视频。测试环境中测试有效。
5.编辑时光标跳转到最后的问题(new~)
使用时发现了这样的bug,即每编辑一下,光标就会跳到文末。
问题来源于:每次编辑富文本会触发editor的onchange
事件,onchange
事件中,通过触发父组件的update:propName
自定义事件,实现富文本内容prop由子组件向父组件的更新(参照vue文档.sync
修饰符部分)。而这又会反过来触发子组件对富文本内容prop的watch
监听(之前我们通过watch
监听来实现父组件接口数据对editor组件富文本框的内容回填),最终导致每一下的编辑,都会让富文本内容重新回填到富文本框一次,出现了光标每次跳转到文末的问题。
解决方案:在子组件data中增加一项数据,用于判断当前是否手动进行了富文本框编辑,如果是,则watch监听中不再将传递来的绑定数据回填到富文本框中。
watch: {
content(newVal, oldVal){
if(!this.isChange){
this.editor.txt.html(newVal);
}
this.isChange = false;
}
},
...
...
mounted(){
...
this.editor.config.onchange = html => {
this.isChange = true;
this.$emit('update:content', html);
}
...
}
6.页面初始化时数据不向富文本框回填的问题(new~)
在上一部分中,我们通过一个值isChange来判断修改来源,并阻断watch监听中的由于手动编辑富文本框造成的数据二次回填问题。
然后,又又又出问题了。。。
修改过后,发现页面在初始化的时候,富文本数据无法正常回填了。。。
打断点,调试,最终发现了问题来源:
由于页面使用了v-if来切换渲染富文本框和其他组件,因此在editor.create
之后,我添加了
this.editor.txt.html(this.content);
来确保组件由于v-if而重新渲染时,能够正确回填内容到富文本框。
也因此导致了以下流程:
父组件用默认数据渲染editor组件 -> editor组件在create
之后调用了this.editor.txt.html(父组件默认数据);
-> 触发了editor的onchange事件 -> isChange变为true -> 父组件通过接口获取真实数据并传递给editor组件 -> editor组件watch监听到了数据变化想要回填 -> 但是isChange因为时true,回填失败。
解决方案:onchange事件中,通过判断数据是否发生了变化,来确定本次修改是否来源于真实修改(由this.editor.txt.html(this.content)
触发的onchange
事件,onchange
事件的参数与this.content
相同)
this.editor.config.onchange = html => {
if(this.content == html){
this.isChange == false
}else{
this.isChange = true;
}
this.$emit('update:content', html);
}
结语
大部分的需求下,我们不需要使用功能过于复杂的富文本控件,使用一个简洁轻量的富文本控件就好。wangEditor就是其中之一。除此之外,其可扩展性好,文档写的也不错,还是很推荐大家使用的。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。