笔者从大学时期就开始接触的前端,在刚去实习的时候就被导师安排去做内网的一个小富文本工具。之后从毕业后干的第一份工作游戏客户端,到现在做着可视化相关的前端工作,都有在做富文本相关的内容。可以说是和富文本编辑器(Rich Text Editor)有着不解之缘。

WYSIWYG

如无特别指出,该系列文章中所说的富文本都是指WYSIWYG模式的编辑器。WYSIWYG是英文"What You See Is What You Get"的缩写,翻译过来就是“所见即所得”。

这类产品中最久负盛名的就是Microsoft Word文档。Word文档提供了诸如字体、颜色、背景色、段落等针对文字样式的支持外,还有各种页面排版以及图片、视频插入等富文本功能。并且也完全满足WYSIWYG的原则(除了跨版本打开Word文档时那令人恼火的排版错乱问题)。

在Web端更是富文本应用大放异彩的地方。刚提到的Word文档很早之前就有了Web版本,除此之外还有大名鼎鼎Google Docs、前些年很火的笔记工具Notion等。国内近些年也兴起了众多类似模式的Web应用,如主打办公协作的腾讯文档、飞书文档,偏向于知识库管理的语雀等。

不同时代的富文本编辑器

回到开发者的视角;富文本应用可以说是前端中的“天坑”领域了。如果想最快的实现一个简易的富文本,那么只需在给DOM节点增加一个contenteditable=true即可让页面变为可编辑的模式。此外还有配套的API-execCommand可实现在编辑区域内撤销、回退、变更文本样式等功能。这么看来,既然有浏览器的这些支持,那么在Web端实现富文本应该并不是一件很难的事。 但坑就坑在了浏览器的兼容性上。各个浏览器厂商对于execCommand支持程度是不同的,为了屏蔽各浏览器的差异而提供一套统一的API给开发者使用,就必须额外地做许多工作。曾经非常著名的CKEditor就是基于该方式实现的。

对于开源界中数量众多的富文本库,个人钟意将其分为两大类:

  • 旧时代的富文本编辑器:代表作CKEditor、TinyMCE、国内百度的UEditor以及众多基于JQuery使用的富文本插件。这些富文本编辑器的最大特点就是“开箱即用”。它们往往都没有太多内置的概念,如果你并没有深入应用的场景,那么遵循官方文档能以非常简单的方式引入便可以在页面中拥有一个可用的富文本编辑器了。并且它们都有预置的极其丰富的各式功能,一般都是在初始化编辑器时以配置的方式传入,以TinyMEC入门文档中的一段代码为例:

    只需在构造函数中传入容器DOM的id和你需要的富文本工具栏的功能集数组,就可以展示出一个完备的富文本编辑器出来了。

    而该类型编辑器的缺点非常明显:(1) 能够支持的功能局限在库本身所提供的功能集,可自定义的程度很低。(2) 没有做Data Model和View的拆分,对于编辑器内容的存储和导出往往是与HTML标签高度耦合的。虽然这种方式非常便于直接展示富文本内容,但如果想对存储内容做遍历分析或回显调整等操作的话则会存在诸多不便的地方。并且存储内容中包括太多的HTML标签和样式信息会大大增加数据的体积。

  • 现代化的富文本编辑器:本系列文章的主角 - Slate.js以及同样是基于React生态的Draft.js都可以称为现代化的富文本编辑器。

    但这两者其实更应该叫做富文本编辑器框架。与上一代的富文本编辑器不同,Draft.js和Slate.js不提供任何“开箱即用”的功能。它们都实现了将Data Model和View层的拆分。在View这一层,两者都是基于React来做内容的自定义渲染。在Data Model层则是有一套框架自己定义的schema格式,在开发过程中主要精力就是关注在这套Data Model上以及从它们到View层的转换。

    作为框架,它们没有任何现成可用的富文本功能,仅是提供一系列开发编辑器所需的基础“元件”和最基本的一套操作API。这就导致了相对于上代编辑器有了更高的上手门槛:哪怕是开发一个再简陋的富文本应用,都需要从零开始实现,因此也有着更大的心智负担和更多的代码量。

接下来

既然本系列文章是解析Slate.js的源码,先来看看Slate这个库中有哪些包:

我们开发者最需要的是两个包:

  • slate 数据模型层。Slate最核心的部分,完全使用Typescript编写,包括了Slate数据模型的定义以及用于操作数据的对外接口。数据模型中的许多类型都是可拓展的(extendable),在后续讲解自定义类型的时候还会细说。
  • slate-react视图层。负责和前端框架React的对接,渲染富文本内容及用户交互的处理。正是由于这种良好的架构,使得开发者除了可以选择直接使用官方的slate-react作为视图层,还可以在不同的前端框架下实现自己的视图层,slate-angular就是一个非常优秀的例子。

至于slate-history包,则是用于为编辑器提供撤销回退操作(undo/redo)的插件,不过笔者还并不打算开slate-history的坑: ) 该系列文章中主要是专注于slateslate-react的源码解析。

笔者从0.62版本开始就开始调研Slate,当时可谓是一把辛酸泪: ( 各种花式Bug和浏览器相关的兼容问题数不胜数;并且出了问题后能搜索到的资料极少,慢慢翻Slate的issue板块也不一定能有解决方案,往往最后之只能用非常hack的方式绕过去。 而在该系列文章,笔者打算基于0.82版本的源码作解析。0.82距最新版本很近,这也是笔者正在使用,已经引入生产环境中并稳定运行了的,曾经已知的许多bug和问题都已经得到了解决: )。

小结

本篇并没有什么实际的干货,笔者只是从自己的角度概述了下在Web端上富文本的分代和它们中典型开源库的介绍,另外再提了下Slate下各个包的作用。但不着急,在下一篇我们就会真正进入到源码之中了:)

slate源码解析(一)- 序言的更多相关文章

  1. 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新

    本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...

  2. 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新

    [原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...

  3. 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新

    上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...

  4. 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...

  5. jQuery2.x源码解析(缓存篇)

    jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 缓存是jQuery中的又一核心设计,jQuery ...

  6. Spring IoC源码解析——Bean的创建和初始化

    Spring介绍 Spring(http://spring.io/)是一个轻量级的Java 开发框架,同时也是轻量级的IoC和AOP的容器框架,主要是针对JavaBean的生命周期进行管理的轻量级容器 ...

  7. jQuery2.x源码解析(构建篇)

    jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 笔者阅读了园友艾伦 Aaron的系列博客< ...

  8. jQuery2.x源码解析(设计篇)

    jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 这一篇笔者主要以设计的角度探索jQuery的源代 ...

  9. jQuery2.x源码解析(回调篇)

    jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 通过艾伦的博客,我们能看出,jQuery的pro ...

  10. HashMap 源码解析

    HashMap简介: HashMap在日常的开发中应用的非常之广泛,它是基于Hash表,实现了Map接口,以键值对(key-value)形式进行数据存储,HashMap在数据结构上使用的是数组+链表. ...

随机推荐

  1. 关于在linux上vm virtualbox读取不到U盘问题的解决

    1.设置usb2.0模式 如果你没安装拓展插件的话,调成usb2.0就会出现无效的配置这个提示,并且启动虚拟机会报 Implementation of the USB 2.0 controller n ...

  2. 【每日一题】【链表or双指针循环条件】2022年2月26日-NC96 判断一个链表是否为回文结构

    描述给定一个链表,请判断该链表是否为回文结构.回文是指该字符串正序逆序完全一致. 思路: public boolean isPail (ListNode head) { ListNode node = ...

  3. 【Java EE】Day14 Servlet、HTTP、Request

    一.Servlet 二.HTTP 三.Request 四.登录案例

  4. 【消息队列面试】15-17:高性能和高吞吐、pull和push、各种MQ的区别

    十五.kafka高性能.高吞吐的原因 1.应用 日志收集(高频率.数据量大) 2.如何保证 (1)磁盘的顺序读写-pagecache关联 rabbitmq基于内存读写,而kafka基于磁盘读写,但却拥 ...

  5. v-if v-for同时使用 解决eslint报错问题

    <template v-for="sec in item.goods"> <div v-if="item.showDetail" class= ...

  6. rate-limit 一款 java 开源渐进式分布式限流框架使用介绍

    项目简介 rate-limit 是一个为 java 设计的渐进式限流工具. 目的是为了深入学习和使用限流,后续将会持续迭代. 特性 渐进式实现 支持独立于 spring 使用 支持整合 spring ...

  7. Spring中11个最常用的扩展点,你知道几个?

    前言 在使用spring的过程中,我们有没有发现它的扩展能力很强呢? 由于这个优势的存在,使得spring具有很强的包容性,所以很多第三方应用或者框架可以很容易的投入到spring的怀抱中.今天我们主 ...

  8. ModuleNotFoundError: No module named 'MySQLdb'

    执行命令 python manage.py makemigrations时抛出以下错误 Traceback (most recent call last): File "D:\Program ...

  9. AWVS漏洞扫描器的使用

    前言 AWVS是一款强大的web漏洞扫描工具,扫描速度快,可针对特定的漏洞进行扫描测试,用于在按全人员对指定企业进行安全扫描以及测试人员对web应用检测漏洞. AWVS使用以及功能介绍 这里介绍的是使 ...

  10. 学会了selenium 模拟鼠标操作,你就可以偷懒点点点了

    前言 我们在做 Web 自动化的时候,有时候页面的元素不需要我们点击,值需要把鼠标移动上去就能展示各种信息. 这个时候我们可以通过操作鼠标来实现,接下来我们来讲一下使用 selenium 做 Web ...