背景
富文本编辑是管理后台(cms)系统中的重要功能,编辑器的选择也非常多,如今大多编辑器都是走的简约路线,遇上挑剔的客户就无法满足他们的需求。百度的ueditor作为一款重量级的编辑器,提供了强大的功能,并且从word中直接copy到编辑器中的还原效果也非常好,但是由于官方已经很久没有维护了,所以对接已有的系统灵活度不够。
基于vue封装的ueditor组件挺多的,并且封装和改造的效果都还不错,比如vue-ueditor-wrap,在封装react-ueditor-component过程中也借鉴了开源社区中的优秀代码。
功能需求
ueditor其他功能没什么需要改动的,但是上传文件的功能与后端耦合太高,不符合现在的前后端分离的系统设计,也不好对接第三方存储(如七牛OSS),所以要改造实现基本的两个功能:
- 后端配置前移,上传文件的配置参数直接写在前端,不需要请求一次后端接口才能初始化上传文件的功能
- 自定义上传文件的请求头和请求,虽然官方提供了解决方案,但是不够灵活
另一块就是基础的编辑功能,封装后的组件应该像input
使用一样简单,value
控制编辑器内容,onChange
监听编辑器内容变化事件
下面解析一些核心功能的实现思路
初始化编辑器
ueditor
的初始化是异步的,所以需要在编辑器准备就绪后才能进行后续的操作,这里使用Promise
进行流程控制
componentDidMount () {
// 编辑器ready后再进行后续操作
this.setState(state => ({
editorReady: new Promise((resolve, reject) => {
let ueditor = window.UE.getEditor(this.editorId, {
...this.ueditorOptions, // 一些默认参数
...this.props.ueditorOptions // props传入的参数
});
ueditor.ready(() => {
resolve(ueditor);
this.observerChangeListener(ueditor); // 初始化监听编辑器变化的方法,后面会具体说明
ueditor.setContent(this.props.value || '');
});
})
}));
}
value
value改变触发react-ueditor-component
中的编辑器的变化是个很简单的父组件向子组件传参,
使用static getDerivedStateFromProps
就可以实现
static getDerivedStateFromProps (nextProps, prevState) {
let editorReady = prevState.editorReady;
let value = nextProps.value;
if (Object.prototype.hasOwnProperty.call(nextProps, 'value')) {
editorReady && editorReady.then((ueditor) => {
(value === prevState.content || value === ueditor.getContent()) || ueditor.setContent(value || '');
});
}
return {
...prevState,
content: value
};
}
上面的代码比想象中复杂一点,在组件内的state
中会创建一个属性content
用于存储上次传过来的value
,props.value
会和content
和编辑器中实际的内容比较
因