「富文本」从 Quill 到 TinyMCE,我爱过恨过,也哭过笑过...

5,002 阅读6分钟

大家好,我是寒草😈,一只草系码猿🐒
如果喜欢我的文章,可以关注 ➕ 点赞,与我一同成长吧~
加我微信:hancao97,邀你进群,一起学习交流,成为更优秀的工程师~

致起始 — 本文其实是冒险故事?!

大家好,我是大寒草 🌿,为什么说我是大寒草呢,因为我这两天被富文本搞的头都大了,一个接一个出乎意料的 bug 的出现迫使我经历了:

  • 用旧爱 Quill 踩坑
  • 被迫寻找新欢
  • 用新欢 TinyMCE 踩坑

所以本篇文章表面上虽然是踩坑实践之路,但是其实是一部充满三方势力爱恨纠葛的冒险故事。

致 Quill — 我并肩作战的旧爱

image.png

故事的最开始是我们组接到这样的一个需求,将原本仅用于展示的邮件模板支持富文本编辑,之前我们系统里已经存在着一个基于 Quill 封装的组件,我得到的话是:“直接用那个组件就好了啊”。

所以第一步很 easy 嘛,拿来主义好,但是事情渐渐偏离了我最初的设想,我遇到的第一个问题开始了!

BUG1: 实际邮件中样式无法生效

没过多久,我就收到了第一个 bug,在富文本中修改的样式,并没有在实际发送的邮件中生效!

我收到这个 bug 的时候就很懵逼,这个基于 Quill 封装的组件在之前的业务里就是用来编辑邮件正文的,为什么偏偏在我这里就出问题了!

这个时候我是怀疑自己的

但是经过我的检查,唔,这个 bug 算是历史遗留了,于是我就开始寻找问题原因。

真相永远只有一个

image.png

富文本中的样式是通过 class 来写的,然而且不说邮件中兼不兼容 class,我们编辑完传给服务端的富文本本身就不会携带 Quill 中的样式。

第一反应看官网,看看有没有将 class 转换为 inline 样式的配置。果然,功夫不负聪明小伙儿,我在官方文档中看到了这样一段:

image.png

原来如此,只要从 'attributors/style/xxx' 中引用并注册就可以转换为行内样式,兴致冲冲的我就去看 Quill 的源码,看到后我甚是灰心。

image.png

仅支持:

  • align
  • background
  • color
  • direction
  • font
  • size

然而实际用到的却比这几个多,比如:缩进。

其实这个时候我就已经在寻找 Quill 的替代品了,TinyMCE 就是这个时候找到的。

然而产品说了一句:“可以接受”,产品姐姐不仅减少了我的工作量,还为我和 Quill 的故事续了一波。

BUG2: 部分邮件模板内容无法于富文本中显示

刚刚由于产品的宽容,我和 Quill 的爱恨纠葛得以延续。但是接下来出现的 bug 使得我不得不抛弃我挚爱的 Quill

产品:“我刚才去线上测试,为什么有一部分内容没有显示出来?”

我当时的第一反应是:“测试又乱改数据了?”

没错,我这个愚蠢的人类居然认为问题如此简单。

然而经过定位,我发现无法显示的内容是 ul 内部嵌套 ol,接着我先会去思考是否为我们对于组件的二次封装又问题,就去官网进行尝试:

image.png

也不行,于是我就有理由认为,继续使用 quill,我们是无法将 ul 内部嵌套 ol 的结构回显出来的。由于项目紧急,我便下定决心,暂时采用别的富文本绕过这个 bug

vue-quill 其实是没有这个问题的,我也很疑惑 🤔~如果有机会我会给出这个问题的答案 ✨

最后

终到曲中人散时,对不起 Quill 💔,只能说爱过,还会爱。任务紧急,实在抱歉。

致 TinyMCE — 我又爱又恨的新欢

image.png

Why TinyMCE

为什么选择 TypeMCE,在选择富文本组件时需要保证两点:

  • 该富文本组件需要支持全部实战化系统富文本中的既有功能
  • 可以解决上文中两个问题,即全部样式支持 inline 模式,以及可以正常显示 ul 嵌套 ol的 dom 结构

还有,其实我又看到我们团队的另一个人曾经说过 TinyMCE 不好看又比较土。但是现在这个场景下我觉得比较好用,那就 ok 吧 ☁️

介绍

以下介绍来自中文官网

TinyMCE 是一款易用、且功能强大的所见即所得的富文本编辑器。同类程序有:UEditorKindeditorSimditorCKEditorwangEditorSuneditorfroala等等。

TinyMCE 的优势:

  • 开源可商用,基于LGPL2.1
  • 插件丰富,自带插件基本涵盖日常所需功能
  • 接口丰富,可扩展性强,有能力可以无限拓展功能
  • 界面好看,符合现代审美
  • 提供经典、内联、沉浸无干扰三种模式
  • 对标准支持优秀(自v5开始)
  • 多语言支持,官网可下载几十种语言。

安装

  • npm i @tinymce/tinymce-vue -S
  • npm i tinymce -S

npm 上有一个 vue 版本的 tinymce,为了更方便的在 vue 中使用,我们可以把 @tinymce/tinymce-vue 以及完整的编辑器包 tinymce 一起安装下来。

注意:vue2中不能使用 @tinymce/tinymce-vue为4以上版本;比如可以:npm install @tinymce/tinymce-vue@3.0.1 -S 而 tinymce 包的版本无所谓

使用

首先注意引用顺序:

import tinymce from 'tinymce/tinymce';
import TinymceEditor from '@tinymce/tinymce-vue';
import 'tinymce/tinymce.min.js';
import 'tinymce/themes/silver/theme';

注意:引用的顺序不一致会有问题

之后引入样式:

import 'tinymce/skins/ui/oxide/content.css';
import 'tinymce/skins/ui/oxide/content.inline.css';
import 'tinymce/skins/ui/oxide/skin.css';

注意:样式必须要引用才可以编辑器才可以正常显示,编辑器需要一个 skin !

mounted 中也需要进行初始化:

mounted () {
    tinymce.init({inline: true});
},

同时在此处配置 inline 为 true

template中使用直接用 v-model 的方式就ok了

<tinymce-editor
    v-model="editContent"
    :init="init"
/>

我在 init 中的配置如下:

{
    height: 300,
    language: 'zh_CN',
    toolbar: 'fontselect | fontsizeselect | bold italic underline strikethrough | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist | outdent indent | link ',
    plugins: 'link lists image code table colorpicker textcolor contextmenu',
    branding: false,
    relative_urls: false,
    remove_script_host: false
};

当然如果要使用 插件就需要引用进来,引用路径如下:

import 'tinymce/plugins/image';
import 'tinymce/plugins/link';
import 'tinymce/plugins/code';
import 'tinymce/plugins/table';
import 'tinymce/plugins/lists';
import 'tinymce/plugins/contextmenu';
import 'tinymce/plugins/colorpicker';
import 'tinymce/plugins/textcolor';

注意:如果字体等下拉选择无法展示需要配置 z-index

.tox-tinymce-aux {
    z-index: 709826033 !important;
}
.tox-tinymce-inline {
    z-index: 709826032 !important;
}

致结束 - 那曲终人未散的冒险故事

image.png

那么,这篇文章就基本结束了,寒草给大家伙儿唱个歌吧:

✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨

最近比较烦 比较烦 比较烦
陌生的城市何处有我的期盼
挥别了家乡的伙伴「Quill」
现在的我更觉得孤单

✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨

伙伴们,欢迎关注点赞我的文章,我会为大家带来更多有趣有料的内容!
下一篇文章我们再会