slate源码解析(一)- 序言
笔者从大学时期就开始接触的前端,在刚去实习的时候就被导师安排去做内网的一个小富文本工具。之后从毕业后干的第一份工作游戏客户端,到现在做着可视化相关的前端工作,都有在做富文本相关的内容。可以说是和富文本编辑器(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的坑: ) 该系列文章中主要是专注于slate和slate-react的源码解析。
笔者从0.62版本开始就开始调研Slate,当时可谓是一把辛酸泪: ( 各种花式Bug和浏览器相关的兼容问题数不胜数;并且出了问题后能搜索到的资料极少,慢慢翻Slate的issue板块也不一定能有解决方案,往往最后之只能用非常hack的方式绕过去。 而在该系列文章,笔者打算基于0.82版本的源码作解析。0.82距最新版本很近,这也是笔者正在使用,已经引入生产环境中并稳定运行了的,曾经已知的许多bug和问题都已经得到了解决: )。
小结
本篇并没有什么实际的干货,笔者只是从自己的角度概述了下在Web端上富文本的分代和它们中典型开源库的介绍,另外再提了下Slate下各个包的作用。但不着急,在下一篇我们就会真正进入到源码之中了:)
slate源码解析(一)- 序言的更多相关文章
- 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新
本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
[原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...
- 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新
上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...
- 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例
前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...
- jQuery2.x源码解析(缓存篇)
jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 缓存是jQuery中的又一核心设计,jQuery ...
- Spring IoC源码解析——Bean的创建和初始化
Spring介绍 Spring(http://spring.io/)是一个轻量级的Java 开发框架,同时也是轻量级的IoC和AOP的容器框架,主要是针对JavaBean的生命周期进行管理的轻量级容器 ...
- jQuery2.x源码解析(构建篇)
jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 笔者阅读了园友艾伦 Aaron的系列博客< ...
- jQuery2.x源码解析(设计篇)
jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 这一篇笔者主要以设计的角度探索jQuery的源代 ...
- jQuery2.x源码解析(回调篇)
jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 通过艾伦的博客,我们能看出,jQuery的pro ...
- HashMap 源码解析
HashMap简介: HashMap在日常的开发中应用的非常之广泛,它是基于Hash表,实现了Map接口,以键值对(key-value)形式进行数据存储,HashMap在数据结构上使用的是数组+链表. ...
随机推荐
- 周立功DTU+温度传感器,ZWS物联网平台尝试
1.前言 了解到周立功有相关的物联网云平台,近期在调研动态环境监控项目,可以进行一个上云的尝试.购置了传感器.周立功的DTU等硬件,将传感器的温度.湿度等数据进行一个云平台的上传. 2.前期准备 传感 ...
- fbterm的配置,纯文本终端显示中文
安装 fbterm sudo apt-get install fbterm 设置普通用户可以执行 fbterm 命令 sudo adduser username video #username为用户名 ...
- C++ 之 宏定义
宏在 C 语言中非常重要,但在 C++ 中却无甚大用,普遍的共识:尽量避免使用宏 C++ 之父 Bjarne 在<C++ Programming Language>中写到 Avoid ma ...
- 乐维监控与Zabbix对比分析(一)——架构、性能
近年来,Zabbix凭借其近乎无所不能的监控及优越的性能一路高歌猛进,在开源监控领域独占鳌头:而作为后起的新锐监控平台--乐维监控,则不断吸收Zabbix,Prometheus等优秀开源平台的优点,兼 ...
- 玩好.NET高级调试,你也要会写点汇编
一:背景 1. 简介 .NET 高级调试要想玩的好,看懂汇编是基本功,但看懂汇编和能写点汇编又完全是两回事,所以有时候看的多,总手痒痒想写一点,在 Windows 平台上搭建汇编环境不是那么容易,大多 ...
- .NET 云原生架构师训练营(基于 OP Storming 和 Actor 的大型分布式架构一)--学习笔记
目录 为什么我们用 Orleans Dapr VS Orleans Actor 模型 Orleans 的核心概念 为什么我们用 Orleans 分布式系统开发.测试的难度(服务发现.通信) 运维的复杂 ...
- 同步与异步 multiprocessing 进程对象多种方法
目录 同步与异步 阻塞与非阻塞 综合使用 创建进程的多种方式 前言 windows系统创建进程的问题(重要) multiprocessing模块之Process 展现异步 创建进程的方式(一):使用P ...
- python 小球碰撞游戏
#小球和挡板要自己找照片,放在一个单独文件夹,音乐也是一样的import pygame pygame.init()#游戏资源加载 a = 700#x轴为700 b = 800#y抽为800 sceee ...
- JavaScript:显式转换数据类型:如何转换为数值、字符串和布尔值类型?
JS的运算符以及某些内置函数,会自动进行数据类型的转换,方便计算,即隐式转换数据类型: 但是很多时候,我们希望可以手动控制数据类型的转换,即显示转换数据类型: 转换为字符串 String()函数 使用 ...
- Visual Studio 2022 MAUI NU1105(NETSDK1005) 处理记录
故障说明 MAUI项目是日常使用的项目,一直都好好的 某一天修改了几行代码后,突然项目无法编译了,提示NU1105错误 从Git重新拉取一份之前的代码编译也是同样的错误,经过半天的查阅,尝试了几种方案 ...