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在数据结构上使用的是数组+链表. ...
随机推荐
- MySQL数据库:7、SQL常用查询语句
Python基础之MySQL数据库 目录 Python基础之MySQL数据库 一.SQL语句常用查询方法 前期数据准备 1.基本查询 2.编写SQL语句的小技巧 3.查询之where筛选 3.1.功能 ...
- Jmeter启动报错: ANOMALY: use of REX.w is meaningless (default operand size is 64), Unrecognized option: --add-opens
摘要:需要远程到其他电脑,把本机的jmeter打包发到远程的电脑上,启动jmeter时报错如下: 原因分析:第一反应无法创建java虚拟机我以为是没有JDK,通过CMD Java -version ...
- JavaScript入门②-函数(1)基础{浅出}
01.JS函数基础 1.1.函数定义 函数(方法)就是一段定义好的逻辑代码,函数本身也是一个object引用对象.三种函数构造方式: ① 函数申明:function 函数名(参数){代码},申明函数有 ...
- 谈谈我的「数字文具盒」 - NextCloud
接下来两篇主要谈论 Nextcloud 和 Obsidian,因为篇幅较长,所以单出罗列出来.本文主要介绍 Nextcloud 以及使用中的技巧和心得体会. Nextcloud Nextcloud 是 ...
- 【每日一题】【迭代器,泛型】2022年1月8日-NC93 设计LRU缓存结构
描述设计LRU(最近最少使用)缓存结构,该结构在构造时确定大小,假设大小为 k ,并有如下两个功能1. set(key, value):将记录(key, value)插入该结构2. get(key): ...
- CountDownLatch闭锁源码解析(基于jdk11)
目录 CountDownLatch闭锁源码解析(基于jdk11) 1.1 CountDownLatch概述 1.2 CountDownLatch原理 1.2.1 基本结构(jdk11) 1.2.2 a ...
- 在Windows服务器安装禅道
1.服务器上 浏览器打开禅道官网:https://www.zentao.net/ 2.下载禅道版本,这里安装的是开源版 3.下载完成之后,一键安装 安装完成之后,即可访问:
- 论文解读丨【CVPR 2022】不使用人工标注提升文字识别器性能
摘要:本文提出了一种针对文字识别的半监督方法.区别于常见的半监督方法,本文的针对文字识别这类序列识别问题做出了特定的设计. 本文分享自华为云社区<[CVPR 2022] 不使用人工标注提升文字识 ...
- JavaScript:对象:如何判断对象是否有某个属性?操作符in
使用in运算符来判断,有返回true,没有返回false:
- (8)go-micro微服务Mysql配置
目录 一 gorm介绍 二 gorm安装 1.1 下载依赖 1.2 使用MySQL驱动 三 CURD操作 1. 查询 1.1 单行查询 1.2 多行查询 2. 插入数据 3. 更新数据 4. 删除数据 ...