概述
富文本即可以理解为web版word,当然没有web那么复杂,现在主流的富文本产品有语雀,腾讯文档这些。可以体验一下这些产品的使用,非常丝滑和复杂。
历史
目前,在富文本领域,具体实现方法大致可以分为三种,L0编辑器、L1编辑器、L2编辑器。他们的区别如下
L0
- 基于浏览器提供的contenteditable实现富文本编辑。
- 使用浏览器的document.execCommand执行命令操作。
在富文本编辑器出现之前,浏览器就已经具备了展示富文本的能力,通过编排HTML和CSS就可以展示富文本的内容,但对于用户输入,浏览器所提供的和都只允许用户输入纯文本的内容,即内部是一个个的文本节点。到后来,contenteditable的出现为节点赋予了编辑其HTML结构的能力,内部可以是嵌套的dom元素。
最初的textarea和input
contenteditable
在div中配置了 contenteditable 后输入内容就会生成dom
然后可以通过 document.execCommand 来给内容添加样式,比如给一段选中文本添加红色。(不过这个方法已经被mdn废弃)
接下来说说execCommand存在一些问题:
-
兼容性:execCommand命令依赖于浏览器,这就会涉及到各个浏览器对该命令的支持程度。MDN中已经明确表示这是一个已经废弃的命令。
-
黑盒子:execCommand命令是由浏览器执行了,就像一个黑盒子,我们只提供了输入(参数),具体的操作是不由我们自身控制,对于开发来说,这是非常不踏实的。 execCommand 命令的返回值是布尔类型的值,表示该命令是否被正确执行。语法是如下:
-
行为不一致:对于同样的功能, execCommand 命令会导致不一样的行为。比如,对于加粗功能,IE浏览器使用的是strong标签 ,而其他浏览器是使用的是b标签;还有其他各种迷惑行为...。这导致同一功能下,各个浏览器的 DOM 可能不一致。
-
功能限制: execCommand 命令并不是全能的,只能实现一些比较简单的功能,比如文字加粗、文字的背景色、颜色、字体、字号、斜体,标题、删除线、下划线等。并且其中字体只能1-7,标题只能是H1-H6。另外,对于稍微复杂一些的功能,比如表格、图片、代码块、附件等,该命令都不能直接实现。
L1
- 基于浏览器提供的contenteditable实现富文本编辑。
- 数据驱动,自定义数据模型与命令的执行。
对DOM Tree已经数据的修改操作进行了抽象,使开发者在大部分情况下,不是直接操作的DOM完成的各种功能,而是使用L1框架构建的模型所提供的API完成的。比如Quill.js、ProseMirror、Draft.js、Slate。其输出为自封装的模型表示的数据。
ProseMirror
首先要定义自己的数据模型,在prosemirror中是要先定义一个schema,schema中分为node和mark
node:node分为block和inline两个类型,和html中的概念类似,block即是一行占一个,而inline是一行内多个。schema使用node来描述在富文本中常见的元素,如标题,段落,代码块,图片等。
mark:mark是schema用来描述样式,只对node上进行样式装饰,如加粗、颜色、字体、字号等等。
在prosemirror组建的富文本中所有输入内容都是由schema约束的。自定义数据结构规定了在渲染时可以渲染成什么样的dom(代码中的toDOM)。以及复制过来的dom统一转化成自定义的数据结构(代码中的parseDOM)。这就类似于vue和react这些框架,有自己定义好的虚拟dom,然后视图渲染时先更改虚拟dom,然后再通过编译器转成真实dom,prosemirror的原理是一致的。
prosemirror先定义好数据结构(model),然后通过model来生成(相当于一个class生成的实时对象)当前的实时数据(state),然后prosemirror所有更改都通过transaction(事务)来修改state。最后再将state渲染成对应的dom结构(通过view层来渲染)
L2
自定义输入和操作,包括光标、输入法、删除等基础动作,具备绘图布局等能力(L1的选区和光标是通过浏览器的Selection和Range来完成的)。主要商业产品包括Google Docs、 Office Word Online。
参考文章: