富文本调研

6,219 阅读6分钟

定义:

富文本编辑器(Rich-Text Editor)简称RTE,是一种可内嵌浏览器,所见即所得的文本编辑器

编辑器实现原理:

大概分为3种:

  1. 在textarea上定位各种样式。这是 Facebook 早期评论系统所使用的。 加粗斜体等操作都难支持, 已经弃用
  2. 实现自己的布局引擎,连闪烁的光标都是通过div控制的。这是 Google Docs 所使用的。 工作量非常巨大, 只有谷歌微软这样的能自己造浏览器的巨头才玩得好
  3. 使用浏览器原生的ContentEditable编辑模式。这是绝大多数现有富文本编辑器所使用的。 打开控制台,在body上加入contenteditable属性,就会变成编辑器,快捷键,撤销栈,光标,输入法, 兼容性浏览器都替你处理好了

开源编辑器:

现在有很多开源编辑器,这里就不一一介绍了,你可以去网上搜索,随便举几个例子

  1. 百度UEditor
  2. ProseMirror
  3. slate
  4. quill
  5. EtherPad
  6. Draft

产品:

  1. 飞书 (字节跳动旗下办公产品)

  2. 语雀 (阿里旗下)

  3. 金山文档WPS(金山办公软件):

    • 光标都是自己开发的
  4. 有道笔记(网易):

    • 一代2012年:当时安卓自带的webview不支持contenteditable
    • 二代:contenteditable特性。但是不同浏览器有差异
    • 三代2015:不再依赖浏览器的contenteditable特性

    有道云笔记发展

  5. 石墨文档(react)

  6. 腾讯文档


调研了3个富文本

一、Quill(个人推荐)

旨在兼容性和可扩展性github

quill 官网是有一些基本功能的,他的核心是blot和parchment,就是DOM树的副本。数据存储方面用的是delta(一个json格式的) 所以你可以在quill的基础上扩展你想要的功能,比如你要自定义个他没有的功能,比如自定义一个分割器大概分为一下几个步骤

  • 继承parchment的blot 的 BlockEmbed
  • 定义一个分割器的 blotName 和tagName
  • 注册到Quill(不注册是Quill是不认识他的)
  • 自定义个button
  • 找到光标所在位置,插入你要插入的内容,并且把光标后移一下
import Quill from 'quill'
let BlockEmbed = Quill.import('blots/block/embed')

class Divider extends BlockEmbed { }
Divider.blotName = 'divider'
Divider.tagName = 'hr'

Quill.register({
  'formats/divider': Divider
})
<!--hrml-->
<button class="custom-hr" @click="insertDivider()"></button>
<!--js-->
insertDivider() { // 自定义的分割线
  let range = this.quills.getSelection(true); //获取光标位置
  if (range != null) {
    this.quills.insertText(range.index, '\n', Quill.sources.USER); // 插入回车符
    this.quills.insertEmbed(range.index + 1, 'divider', true, Quill.sources.USER); //在光标+1的位置插入一个<hr>标签
    this.quills.setSelection(range.index + 2, Quill.sources.SILENT); // 将光标往后移一个
  }
},

缺点:

不支持表格,支持表格的是dev2.0版本,但是未发布,虽然可以投入到生成中,但是最大的问题是如果你使用了dev2.0版本,很多插件比如@提及功能,多选框等功能 不支持在2.0中使用的

兼容性:

数据存储格式Delta:

  1. Quill.getContents():
    {"ops":[{"insert": "\n", "attributes": {"background": "red"}}]}
    
  2. Qull.setContent(delta) : 文档的回显

二、ProseMirror(特点:灵活,配置项强)

1.定义:

prosemirror不是一个大而全的框架,它是由无数个小的模块组成,它就像乐高一样是一个堆叠出来的编辑器。

2. 四个核心库(就像4个轮子)

  1. prosemirror-model:定义编辑器的文档模型,用来描述编辑器内容的数据结构
  2. prosemirror-state:提供描述编辑器整个状态的数据结构,包括selection(选择),以及从一个状态到下一个状态的transaction(事务)
  3. prosemirror-view:实现一个在浏览器中将给定编辑器状态显示为可编辑元素,并且处理用户交互的用户界面组件
  4. prosemirror-transform:包括以记录和重放的方式修改文档的功能,这是state模块中transaction(事务)的基础,并且它使得撤销和协作编辑成为可能。

3. 数据存储

import {EditorState} from "prosemirror-state" 解析器:DOMparse 或者MaekdownParser 把dom渲染成一个Node对象。 序列器: 调用EditorState.JSON()可以把当前状态doc序列成json格式

4. 缺点

  1. 学习曲线稍微陡峭:文档都是英文,中文资料少,有问题就去github上找

三、 slate框架

定义:

所有逻辑通过一系列的插件实现的。灵感来源如Draft.js,ProseMirror,Quill等类库。你可以将它理解为在React 和Immutable基础上,一种可插拔的 contenteditable 实现.目前还在beta测试状态,社区驱动

支持程度:移动端:支持ios,但是没有定期测试。 0.47 支持安卓on 谷歌,但是0.50+ 当前不支持, 支持ios pc端最新的谷歌,Edge,火狐,safari 进行了测试,在IE中不行

  • 开发语言:JAVA
  • 授权协议:MIT
  • 数据存储格式: JSON
  • 操作系统:跨平台
  • 对等依赖:React
  • 数据结构:immutable (ProseMirror的)
  • 版本:0.1.0 - 0.57.0 (2019年12月18号)
  • 秒崩bug知乎2019-12-26
  • 传说的表格和协同编辑只是理论上支持,需要大牛搞

immutable 是FaceBook开发的不可变数据集合。不可变数据一旦创建就不能被修改,使得应用开发更简单,允许使用函数式编程技术,比如惰性评估。允许高效的队列方法链,类似 map 和 filter ,不用创建中间代表。 immutable 通过惰性队列和哈希映射提供 Sequence, Range, Repeat, Map, OrderedMap, Set 和一个稀疏 Vector。

优点:

  • 支持所有浏览器
  • api文档很好,发展迅速,社区活跃,作者修改还比较积极
  • 链式操作:实现协同编辑
  • 使用immutable(不可修改,js对象属性是可以修改的)不存在引用问题, 子节点随意的改动都会生成一颗新树,可以轻松实现富文本的撤销和重做操作。并且支持完全复杂的嵌套开表达文档的树形结构。

在slate 和Draftzhong ,富文本数据就是对immutable的一层封装, 从而自带了对撤销操作的支持不需要额外编码实现,但是Slate 比Draft多了支持嵌套的数据结构

编辑操作时发生的处理流程:

  1. 用户在编辑器光标所在的 Node 内按键,触发事件。
  2. 根据按键的键值,分发不同的 Change,如换行、加粗等。
  3. Change 修改 State,生成新 State。
  4. 新 State 经过 Schema 校验后,渲染到编辑器内,按需更新相应的 Node。

整个流程中最核心的机制可概括为一个公式:state.change().change(),Change 是一个非常优雅的 API,所有的变换都是都通过 Change 对象实现的。

对比:

对比 slate ProseMirror Quill
watch 295 130 479
start 16.2k 4.2k 25k
fork 1.6k 230 2k
数据存储 JSON JSON JSON输入输出
支持程度 0.5+不支持安卓 兼容性很好基本都支持
特点 依赖React,immutable 四个核心库,配置灵活 开箱即用
推荐指数 不推荐,输入法有bug 推荐 推荐

quill开发H5缺陷:

  1. h5限制:光标会和键盘一起出现

点击加粗格式,聚焦文本时都会引起键盘的弹起,如果你的格式设置放在页面的底部,就会被键盘挡住, 并且键盘的时而弹起也会非常影响体验

  1. 安卓 ios 兼容性

安卓不支持选中

总结:

推荐文章:

  1. Slate.js - 革命性的富文本编辑框架
  2. 各种富文本框架比较