本文由智能化研发管理工具PingCode前端工程师 杨振兴 分享

一句话介绍

slate-angular 是一个基于 Angular 和 Slate.js 的编辑器视图层,帮助开发者使用 Angular + Slate.js 构建Web富文本编辑器。

Slate.js 介绍

Slate.js 是一个特别优秀的富文本编辑器框架,代码整洁、架构良好、扩展性强,目前市面上基于 Slate.js 开发的富文本编辑器及产品已经数不胜数。而且 Slate.js 足够有魔力,从开始接触富文本编辑器开发到现在两年左右的时间,感觉 Slate.js 一直是我成长的良师,从最初的入门调研,到开发出第一个版本编辑器,然后是视图层架构的升级,再到后面的性能及稳定性的优化,每一个阶段都能从 Slate.js 身上学到很多东西,当然对它的了解也越来越深。我觉得 Slate.js 就是一个自身在不断地迭代和改进的编辑器框架,专注于视图层和模型层,架构实现一直紧跟社区主流技术的发展,内容编辑的实现机制也在不断地向现行标准事件靠拢,已经开源5年左右的时间,目前社区仍然非常活跃,还在不断地扩展更多的适用场景,是非常厉害的一个存在。

自研Angular视图层

我们的前端技术栈是 Angular,开源社区中基于 Angular 开发的富文本编辑器极其稀缺,而我们要做的 PingCode Wiki 产品又对富文本编辑器的易用性和可扩展性要求极高,调研发现Slate编辑器框架非常符合我们的需求,核心模型层不依赖任何前端框架,可扩展性极其高,有完整的测试覆盖,所以我们尝试自研基于 Angular 的视图层,可以理解为自研视图层的核心驱动来源于产品。

个人觉得开发基于 Angular 的视图层是一个很有意义的过程,并且当前开源社区中还没有使用 Angular 开发 Slate 编辑器的实现,所以我们想把我们的这种实践成果开源出去,以回馈 Slate 和 Angular 社区,让更多的开发者可以基于 Angular + Slate 开发富文本编辑器。

开源之路

当前 slate-angular 已经支持企业级知识库产品 PingCode Wiki 稳定运行超过1年,最初版本是基于 Slate@0.47.0版本(JavaScript版本Slate),第二版是基于最新Slate的实现(TypeScript),当前已经是第三版,从年初就开始准备,包括公开Github仓储、统一底层的实现及API风格、搭建在线Demo、补充单元测试、同步升级最新 Slate 等。

Demo 功能:

github:https://github.com/worktile/slate-angular

demo :http://slate-angular.ngnice.com/

slate-angular 可能不是一个开箱即用的富文本编辑器,它属于Slate框架的一个视图层,对接Slate框架底层与用户交互界面的一个中间层,它仅提供基础的富文本编辑能力和功能扩展的插槽,但这也是slate-angualr的优势,它只专注底层的实现:兼容浏览器、移动端、代理输入事件、代理光标、支持自定义Element/Text/Leaf节点的渲染、处理基础交互等,基于它可以很快开发出像 Quill、Prosemirror 这类有一定基础功能的富文本编辑器,并且它的可扩展上限很高,经过一定的时间完全可以构建出像 Confluence、Notion、PingCode Wiki 这种功能级别的富文本编辑器。

特性支持

  • 集成块级元素前后光标方案

支持扩展指定元素渲染前后光标,方便在块级元素前后插入段落(表格Demo中已经实现块级光标的基本交互)

  • 自定义组件/模版渲染块级元素

支持多层级元素内容的自定义渲染,可方便实现像表格这类复杂场景的需求,同时维持了自定义组件之间的正确的依赖注入链,也就是单元格组件可以通过依赖注入获取父级表格组件的服务

  • 自定义渲染 Text

支持自定义Text节点的内容渲染,这个在 slate-react 中是不提供的,slate-angular 中单独提出来了,主要用于实现加粗、斜体、下划线、颜色、背景色等需求

  • 自定义渲染 Leaf

支持自定义Leaf 节点的渲染,Leaf是对Text的拆分,每一个Text节点默认对应一个Leaf,而Text节点拆分Leaf的依据是Decoration装饰器,主要用于实现对文本的动态修饰,配合自定义Leaf组件实现搜索高亮、划词评论等需求

  • Decoration 装饰器

提供对文本内容的动态修饰,是由外部数据驱动定位、装饰文本内容。它的特点是在不改变原始数据的情况下实现对文本的装饰,是处理动态需求的一种方式

  • Void元素

Void意为不可编辑,所有内容属于一个整体,slate-angular 支持扩展Void元素,通过Void元素可以把任意复杂的Angular组件的嵌入到编辑器中,比如图片、代码编辑器、甘特图等都可以嵌入到编辑器内容区域中。

兼容浏览器

Chrome、Edge、Safari、Firefox、QQ Browser

已解决常见Slate.js兼容问题

  1. 中文输入重复问题

  2. 中文输入崩溃

  3. Safari浏览器输入中文焦点跳动

  4. \n 导致内容混乱

  5. a标签 导致内容混乱

  6. 表格结构约束问题

  7. angular comment问题

  8. ...

这些问题当前已经在 slate-angular 中得到解决,在此不做更多的说明,如有任何疑问欢迎给 slate-angular 提 Issues。

技术路线

接下来聊点技术相关的内容,个人其实一直想对 Slate.js 的架构设计以及内部机制进行一些剖析,所以借助这次开源跟大家简单聊聊 slate.js 和 slate-angular 的技术路线以及比较重要的一些底层机制。

先从 Slate 架构说起:

Slate 框架核心主要包含模型层和视图层,模型层定义描述富文本内容的基本数据结构(一个支持嵌套的节点树)和对该数据的基础操作,视图层对接前端框架,处理基础输入行为、选区代理,内容渲染、插件扩展等等。

值得一提的是Slate的数据模型定义都是都是参照DOM标准实现的,对新手还算友好,比如数据模型的概念Block、Inline-block、Text等都跟DOM中的意义一致,选区也一样有Selection、Anchor、Focus、Collapsed等概念。

Slate 富文本编辑器架构概貌:



基于Angular开发富文本编辑器

slate-angular 作为一个独立的视图层,是Slate底层与上层功能实现之间的桥梁,核心作用就是发挥框架的优势,更好的组织编辑器功能的开发。

基于 slate-angular 开发富文本编辑器可以说是原汁原味的Angular味道,无论是基础功能修改、还是扩展新功能,你都可以使用Angular组件或者服务组织代码的实现,而不再是使用组件对JavaScript库进行简单的封装:

你可以使用 Angular 组件或者模板自定义插件的渲染。

你可以基于 Angular 组件封装复杂的交互行为。

你可以复用 Angular 组件库。

你也可以使用服务在父子级节点组件之间共享数据,它们维持了正确的依赖注入链。

总之 Angular 的一切特性你都可以使用。

内容编辑基础原理

当前技术框架下想实现对输入内容的控制大概有两种实现思路,一种是事件代理,另外一种是监控内容变化,Slate主要采用的是事件代理,就是通过监控一系列内容输入的DOM事件,然后通过事件类型及其它上下文判断该输入对应的数据操作,最后把它转化为针对数据模型的一系列操作。

监控内容变化的方式在Slate中也有用到,是为了支持Android浏览器,大概是因为Android浏览器下某些场景的输入事件无法被正确捕获,进而无法响应用户的操作,所以使用MutationObserver监控内容变化以正确响应用户的输入行为。

因为视图层中事件代理的实现主要是与输入事件打交道,各个浏览器对于输入事件的实现不完全统一,加上又要区分普通英文输入和中文组合输入,所以需要针对不同浏览器做很多兼容性处理,可以说打的是一套组合拳,招式概览:

  1. 理想情况下:使用beforeinput事件完成基础输入代理,因为 beforeinput 语义化清晰,可以作为输入行为判断标准。

  2. 非理想情况:浏览器不支持 beforeinput 事件,使用React的合成事件onBeforeInput处理英文输入(Angular中需要自己实现),对于其它输入交互如回车、删除使用keydown事件处理。

  3. IME输入处理使用事件compositionstart和compositionend处理,这三个事件非常可靠,没有任何浏览器兼容性问题。

  4. 除此之外撤销/重做、焦点移动等是在keydown事件中处理,复制、剪切等逻辑使用原生 copy、cut事件即可,而粘贴、拖拽等逻辑和基础输入一样依赖beforeinput事件,如果浏览器不支持 beforeinput事件则在paste、drop等事件中处理。

事件代理过程概貌:





选区同步机制

和浏览器的选区一样,Slate的数据模型也需要选区,当数据变更发生时标识数据修改的位置,并且这个位置需要跟浏览器原生的选区保持一致,无论是浏览器的选区变化了,还是Slate的选区变化了都需要实现互相同步。

下面介绍下 slate-angular 视图层中选区的双向同步机制:

一、DOM Selection -> Slate Selection:

监控原生Document对象的 selectionchange 事件,当DOM Selection改变时查询对应的Slate Selection,修改Slate Selection与DOM Selection一致。

交互行为 -> DOM Selection 改变 -> selectionchange -> sync Slate Selection

交互行为包括鼠标Click、按方向键等

二、Slate Selection -> DOM Selection:

Slate数据Change导致Slate Selection发生变化,需要在Change事件中做处理,根据最新的Slate Selection查询对应的DOM Selection,修改DOM Selection与Slate Selection一致。

交互行为 -> 触发数据更新 -> 新的Slate Selection -> 视图刷新 -> sync DOM Selection

插件扩展

Slate 使用插件来扩展编辑器功能,并且插件是一等公民(slate-angular也可以理解为是一个基础插件),任何高级交互都可以通过开发编辑器插件来实现。

一、可重写方法

Slate 底层通过抽象出一个一个的可重写方法(deleteBackward、insertBreak、insertText、apply等等)供外部扩展,比如我要实现粘贴时识别Markdown数据格式,可以重写insertText实现,实现回车的特殊处理可以重写insertBreak,相比直接暴露基础事件,提供可重写方式是一个很高级的实现,在slate-angular视图层也单独提供了几个可重写的方法:insertData(处理粘贴数据)、isBlockCard(块级卡片)、onError(错误处理)、onKeydown(基础事件)。

二、自定义渲染

视图层UI部分主要由三层渲染组成,对应三个层级的数据:Element、Text、Leaf ,每一个层级的数据都支持自定义组件/模版渲染,主要是通过renderElement、renderText、renderLeaf实现。

视图层自定义渲染组件的过程概貌:





这部分主要介绍跟 slate-angular 关联比较大的几个部分:组件化开发编辑器、事件代理、选区同步、插件扩展等,核心还是希望大家可以更多的了解 slate.js 以及 slate-angular,技术上就点到为止,有兴趣的可以阅读源代码或者其它技术资料。

写在最后

富文本编辑器是前端中非常复杂的一个领域,未来的道路还很长,我们也希望有更多的开发者能够参与进来,发现并解决诸如浏览器兼容性、兼容移动端、中文输入、标准交互的问题,优化输入代理的机制,优化底层架构,探索基于Slate的协同方案等等。

如有任何问题,欢迎大家给 slate-angular 提 Issues 或者 PRs !

slate-angular 正式开源相关推荐

  1. mac webpack 版本_晓前端周刊 第48期:EMP面向未来微前端方案正式开源了!玩转 webpack,使你的打包速度提升 90%;...

    业界动态 苹果最大杀招:iPhone App 已能在电脑运行 近日网友反馈,苹果 App Store 中大量应用在兼容性一栏中显示:已支持运行 macOS 11(及以上版本)的 Mac 电脑.这意味着 ...

  2. 重磅!阿里巴巴Blink正式开源,重要优化点解读\n

    喜大普奔!阿里巴巴终于在今天正式放出了内部Flink版本Blink的开源项目地址! 在1个月前的Flink Forward China峰会上,阿里巴巴集团副总裁周靖人宣布Blink 将于2019 年1 ...

  3. 基于 Flutter 的 Web 渲染引擎「北海」正式开源!

    简介: 阿里巴巴历时 3 年自研开发的 Web 渲染引擎北海(英文名:Kraken)正式开源,致力打造易扩展,跨平台,高性能的渲染引擎,并已在优酷.大麦.天猫等业务场景中使用. 作者 | 染陌 来源 ...

  4. 又被 AI 抢饭碗?2457 亿参数规模,全球最大中文人工智能巨量模型 “源1.0”正式开源...

    作者 | 伍杏玲 出品 | AI科技大本营(ID:rgznai100) 输入: 昔我往矣,杨柳依依. 今我来思,雨雪霏霏. 行道迟迟,载渴载饥. 我心伤悲,莫知我哀! (以战争为题写一首诗) 回复: ...

  5. GEMM性能提升200倍,AutoKernel算子优化工具正式开源

    作者 | OPEN AI LAB 研究员 吕春莹 出品 | AI科技大本营 头图 | CSDN下载自视觉中国 随着AI技术的快速发展,深度学习在各个领域得到了广泛应用.深度学习模型能否成功在终端落地应 ...

  6. 腾讯 JDK 11 正式开源,高性能、太牛逼啦!

    点击关注公众号,Java干货及时送达 大家好,我是基基. 今天,基基,跟大家分享一下,腾讯2021年开源的 JDK11 ,腾讯大数据JVM团队在Kona JDK11开源项目中,坚持了一贯的兼容性.可靠 ...

  7. 刚刚,华为全场景 AI 计算框架MindSpore正式开源!国产深度学习框架的春天来了!...

    关注上方"深度学习技术前沿",选择"星标公众号", 资源干货,第一时间送达! 此前,我们刚刚报道了旷视科技在3月25日开源深度学习框架 MegEngine ,3 ...

  8. 本人制作的股票技术分析软件正式开源(.net wpf)

    为什么80%的码农都做不了架构师?>>> 本人制作的股票技术分析软件正式开源 该软件以股票数据为核心,尤其以按日数据为主,采用图表方式可视化股票数据 ,为用户提供简单的股票选择可视化 ...

  9. 腾讯 Node.js 基础设施 Tencent Server Web 正式开源

    开发四年只会写业务代码,分布式高并发都不会还做程序员? >>>   经过六年的迭代与沉淀,腾讯Tencent Server Web (以下简称TSW)这一公司级运维组件于今日正式开源 ...

最新文章

  1. 面试大厂背怼!这都搞不定,你只能做“搬运工”!
  2. OpenCV下的灰度直方图生成及显示的源码,带详细注释
  3. docker安装mysql远程不能访问,虚拟机中docker安装mysql远程无法访问解决方法
  4. 批量调整word表格根据窗口调整内容
  5. Spring Boot 企业实战_前夕
  6. docker 删除镜像时报错Error response from daemon: conflict: unable to delete xxx (must be forced) -
  7. go 获取内核数_Go的GPM多线程调度
  8. 【目标跟踪】|MOSSE原理及对应代码解释 matlab C
  9. 浅谈CDN技术的发展历程
  10. Brocade FOS下载 博科光纤交换机固件升级
  11. 用户帐户控制组策略和注册表项设置
  12. video autoplay失效
  13. verilog分频电路
  14. 无限火力服务器爆炸,lol:无限火力这些英雄打架,腾讯看的都紧张,打到服务器爆炸!...
  15. window系统使用 bash 新建 vue3+ts 项目以及 preset 模板使用
  16. SAP MM 供应商无英文名称,ME21N里却带出了英文名字?
  17. 二、基础SpringBoot2.0.0M4项目目录讲解
  18. 智慧城市建设 这五个方面不可不考虑
  19. arm-linux-gcc电子相册,基于TQ2440的电子相册项目实现
  20. 计算机视觉--图像的拼接融合

热门文章

  1. 0x51.动态规划 - 线性DP(习题详解 × 10)
  2. e class connect.php,剖析帝国CMS核心文件e/class/connect.php中的常用函数
  3. A - 棋盘问题 POJ - 1321(dfs)
  4. html中隐藏溢出怎么写,html-如何隐藏表行溢出?
  5. linux单 网卡添加多个网段的ip,[转载]linux 单网卡来绑定多IP实现多网段访问以及多网卡绑定单IP实现附载均...
  6. php限定名称写法,php命名空间:非限定名称、限定名称、完全限定名称实例详解...
  7. part.write java_使用javax.servlet.http.Part类上传文件
  8. 2020移动apn接入点哪个快_为什么都是4G网你的就没别人快?跟我这样设置,网速直线提升...
  9. idea log 不输出error_还在使用console.log()吗?Bunyan:一个简单易用的JS日志框架
  10. 调用实现天气预报功能android,Android编程实现获取新浪天气预报数据的方法