富文本编辑器的技术演进
2020-02-23 264浏览
- 1. 富⽂文本编辑器器的技术演进 罗龙浩 蚂蚁金服高级前端技术专家,语雀文档编辑器负责人
- 2. 在此键入姓名 在此键入tittle
- 3. ⾃自我介绍 2008~2014:业余时间研发 KindEditor,经历 3 个版本的重写 2012~2014:土豆网前端架构师、前端负责人 2014~2018:支付宝行业前端负责人、口碑前端负责人 2018~至今:语雀文档编辑器负责人
- 4. ⽬目录 一、富文本编辑器介绍 二、语雀文档编辑器面临的问题与解决思路 三、多人实时协同的解决思路
- 5. 富⽂文本编辑器器 - 常⻅见交互 富文本输入框 - 输入内容 - 选中 & 操作 操作栏 - 顶部工具栏 - 侧边栏 - 内嵌工具栏
- 6. 富⽂文本编辑器器 - 浏览器器特性
富文本输入框
这里可以编辑对内容进行操作 document.execCommand(‘bold’);
- 7. 富⽂文本编辑器器 - 技术类型 类型 描述 典型产品 L0 1、基于 contenteditable 2、使⽤用 document.execCommand 3、⼏几千~⼏几万⾏行行代码 早期的轻量量级编辑器器 L1 1、基于 contenteditable 2、不不⽤用 document.execCommand,⾃自主实现 3、⼏几万⾏行行~⼏几⼗十万⾏行行代码 CKEditor、TinyMCE Draft.js、Slate ⽯石墨墨⽂文档、腾讯⽂文档 1、不不⽤用 contenteditable,⾃自主实现 2、不不⽤用 document.execCommand,⾃自主实现 3、⼏几⼗十万⾏行行~⼏几百万⾏行行代码 Google Docs Office Word Online iCloud Pages WPS ⽂文字在线版 L2
- 8. 富⽂文本编辑器器 - 不不同类型的优劣 类型 优势 劣势 L0 技术⻔门槛低,短时间内快速研发 可定制的空间⾮非常有限 L1 站在浏览器器肩膀上,能够满⾜足 99% 业务场景 ⽆无法突破浏览器器本身的排版效果 L2 技术都掌控在⾃自⼰己⼿手中,⽀支持个性化排版 技术难度相当于⾃自研浏览器器、数据库
- 9. 富⽂文本编辑器器 - L1 编辑器器 传统模式 DOM 树等于数据,调用各种 DOM API 进行操作 典型产品:CKEditor 4、TinyMCE、UEditor MVC 模式 数据和渲染分离,实现一套操作数据模型的方法,数据变更带动渲染 典型产品:CKEditor 5、Draft.js、Slate
- 10. 富⽂文本编辑器器 - L1 编辑器器两种模式优劣 传统模式 优势:20 年的历史,代码简单直接,可维护性好,充分利用 contenteditable 特性 劣势:代码写法不符合潮流,都是 10 几年前的技术 MVC 模式 优势:代码写法符合潮流 劣势:引起数据和渲染不同步的问题,因为这个机制需要有完全控制用户输入的前提, 实际上基于 contenteditable 没办法控制用户的所有输入,第三方输入法、壳浏览器 会让用户输入不可控
- 11. 富⽂文本编辑器器 - L2 编辑器器 自主实现富文本输入框,包含用户输入和排版引擎,可用 DOM、SVG 技术 用户输入: 光标、选区自主实现,光标位置放隐藏 textarea 接受键盘输入,输入完成之后变更数 据、渲染视图 排版引擎: 实现各种个性化的文字排版、图文布局,突破浏览器排版限制
- 12. 富⽂文本编辑器器 - 总结 L0 L1 L2 技术类型 传统模式 MVC 模式 如何技术选型? 没有编辑器研发团队:推荐基于 CKEditor 4、TinyMCE 二次开发 有几人编辑器研发团队:推荐自研 L1 传统模式编辑器 有几十人编辑器研发团队 & 需要个性化排版:推荐自研 L2 编辑器
- 13. ⽬目录 一、富文本编辑器介绍 二、语雀文档编辑器面临的问题与解决思路 三、多人实时协同的解决思路
- 14. 语雀编辑器器 - ⾯面临的问题 疑难杂症多 问题难以修复,页面崩溃、光标错乱、粘贴卡死等 排查链路长 语雀编辑器、Slate、React 一层层往下查 新增功能难 很多个性化需求,在 Slate 架构上实现成本较高
- 15. 语雀编辑器器 - 根本问题 技术选型问题 1)基于 Slate,是 L1 MVC 模式 2)基于 React 渲染,但 React 是 UI 构建库
- 16. 语雀编辑器器 - 技术选型 L0 L1 传统模式 L2 MVC 模式 更换技术选型,用 L1 传统模式重写编辑器 为什么没有基于开源编辑器? 第一是 license 问题,第二是我正好具备多年 L1 编辑器研发经验 :)
- 17. 语雀编辑器器 - 技术⽬目标 高健壮性 采用一切手段保证功能的稳定,努力做到业内问题最少的编辑器 可维护性 编辑器本身代码量很大,后期可维护性是关键,能用简单方式解决问题,尽量简化 可扩展性 具备良好的扩展性,不能因为架构问题,满足不了业务需求
- 18. 语雀编辑器器 - 开发思路路 数据格式:在 HTML 基础上扩展 卡片机制:承接组件的扩展,在编辑器里独立的一块区域 开发模式:Hybrid 混合开发,编辑区域用原生 JS,UI 层用 React 技术原理:基于 contenteditable,通过 Range API 对选中的内容进行操作
- 19. 语雀编辑器器 - 数据格式
heading
bold italic underline fontcolor backcolor alignment
- orderedlist
光标 选区 HTML 卡片组件 - 20. 语雀编辑器器 - 卡⽚片机制 卡⽚片⼯工具栏 卡⽚片内容区域(contenteditable = false) Left Cursor Right Cursor
- 21. 语雀编辑器器 - 卡⽚片类型 Inline Card Block Card
- 22. 语雀编辑器器 - 混合开发模式 红色区域:原生 JS 蓝色区域:React
- 23. 语雀编辑器器 - 为什什么⽤用混合开发模式? 统一不一定是最佳选择,还是要看带来的业务价值 有两个成功案例: 1)移动端 Hybrid 开发(Native + H5) 2)丰田、本田的 Hybrid 汽车(电机 + 内燃机)
- 24. 语雀编辑器器 - 丰⽥田混动系统 起步 正常⾏行行驶,有剩余能量量 低速⾏行行驶 急加速 正常⾏行行驶,⽆无剩余能量量 减速,充电
- 25. 语雀编辑器器 - 键盘输⼊入定制
- 26. 语雀编辑器器 - contenteditable 问题
光标无法移动到空标签里:
|
、| 光标漂移到 inline-block 右侧:|
光标无法精确控制: 无法输入中文:emoji|
- 27. 语雀编辑器器 - contenteditable 解决⽅方案
光标无法移动到空标签里:
、| 光标漂移到 inline-block 右侧:
||
光标无法精确控制: 无法输入中文:emoji|
- 28. 语雀编辑器器 - Range 介绍 1、开始位置和结束位置通过 container 和 offset 标记位置 2、在文本之间:container 为 TextNode,offset 为从第一个字符到当前位置的偏移量(第几个字 符) 3、在节点之间:container 为父节点,offset 为从第一个子节点到当前位置的偏移量(第几个子节 点) 4、开始位置等于结束位置, range.collapsed 为 true,也就是光标状态 5、开始位置不等于结束位置,range.collapsed 为 false,也就是选择一段内容的状态
- 29. 语雀编辑器器 - Range 示例例
a
bc
range.startContainer = abc; range.startOffset = 1; range.endContainer = abc; range.endOffset = 1; range.collapsed = true; range.startContainer = p; range.startOffset = 0; range.endContainer = p; range.endOffset = 0; range.collapsed = true;abc
range.startContainer = abc; range.startOffset = 0; range.endContainer = abc; range.endOffset = 3; range.collapsed = fasle; range.startContainer = p; range.startOffset = 0; range.endContainer = p; range.endOffset = 1; range.collapsed = false;abc - 30. 语雀编辑器器 - 性能对⽐比 语雀⽂文档 Google Docs 腾讯⽂文档 ⽯石墨墨⽂文档 加载时间 2 秒 3 秒 3 秒 8 秒 粘贴时间 4 秒 7 秒 6 秒 14 秒 操作响应 有点卡 顺畅 ⽐比较卡 ⽐比较卡 测试设备:2015 款 MacBook Pro 15,Chrome 77.0.3865 测试数据:https://shimo.im/docs/keW3LxVd2vQHxUHD/read 声明:由于每个产品的定位、功能复杂度有差异,测试结果好,不不代表编辑器器整体领先,只能说明某⼀一⽅方⾯面有优势。
- 31. 语雀编辑器器 - 时间节点 2018.08:技术选型,开始研发 2018.09:基础编辑 demo 演示 2018.11:讨论区、评论小型编辑器上线 2019.01:文档编辑器上线 2019.03:旧版编辑器全部替换完成,整体运行平稳
- 32. 语雀编辑器器 - 总结 一、根据当前主要问题和后续产品方向,选择合适的技术方案 二、对于绝大多数业务,L1 传统模式编辑器是合适的选择 三、利用好现有的资源,可以用 React、Vue 成熟的组件搭建外围的 UI 层
- 33. ⽬目录 一、富文本编辑器介绍 二、语雀文档编辑器面临的问题与解决思路 三、多人实时协同的解决思路
- 34. 多⼈人实时协同 - 新的挑战 今年 3 月份,我们 PD 找我说
- 35. 多⼈人实时协同 - 语雀⽂文档
- 36. 多⼈人实时协同 - 语雀表格
- 37. 多⼈人实时协同 - 分析竞品 调研对象:Google Docs、Etherpad、 CKEditor 5、Slate、Quill 结论:都用 OT(Operational Transformation) 或类似的技术,将操作转化成 OP (operations),发送到协作服务,再转发给其它在线用户。所以都具备原子化的操作 API,所有的高级操作都通过原子化 API 完成,实时协同只需要将这些原子化 API 的调 用信息转化成 OP 即可
- 38. 多⼈人实时协同 - 开源编辑器器的原⼦子化 API Quill:insert、delete、retain、format Slate:insert_text、remove_text、insert_node、merge_node、 remove_node、move_node、set_node、split_node CKEditor 5:insert、move、detach、merge、split、attribute
- 39. 多⼈人实时协同 - 想法⼀一 改成 MVC 模式 引入 DataModel、抽象原子化 API,但这个意味着重新开发一套编辑器,工作量巨 大,很可能重回 Slate 老路,丢失我们自己的优势,稳定性、易维护、粘贴性能等
- 40. 多⼈人实时协同 - 想法⼆二 封装原子化 API 能不能封装 insertNode、removeNode、mergeNode、splitNode 等原子化 API,所有上层操作都基于这些 API,是否可行? 但几乎所有代码都要修改,影响面完全不可控
- 41. 多⼈人实时协同 - 想法三 DOM diff 方案 能不能每次操作之后直接对比变更前后的 2 个 DOM 树,生成 JSON 格式的 diff,是 否可行? 最大问题是性能,虽然能通过局部 diff 提升性能,但每次操作都要 diff 有点夸张。
- 42. 多⼈人实时协同 - 想法四 全量 command 机制 引入新的 command 机制,所有的变更都通过 command 完成,变更之后产生对应 的 OP,包含 backward 逆向操作 看起来可行 开始 demo 开发,发现编写 command 是非常复杂的事情,写 backward 逻辑成本 太高
- 43. 多⼈人实时协同 - 想法五 在 DOM 底层实现 我们的目标是增加实时协同能力,功能的稳定性比较重要,现在的优势不能丢失,日常 迭代和新功能开发还是要持续进行。所以只能在现有代码上进行改进和扩展,不能推翻 重来 只有一条路,在 DOM 底层做文章 其实 DOM 树相当于 DataModel,DOM API 相当于原子化 API
- 44. 多⼈人实时协同 - ⽣生成 OP 通过浏览器的 MutationObserver API,获取 DOM 树的变更信息 Example Compatibility
- 45. 多⼈人实时协同 - OT 服务 采用 ShareDB,实现了 OT 算法,提供一个基于 JSON 的 OT 通用能力
- 46. 多⼈人实时协同 - 解决⽅方案 OT 服务:基于 ShareDB 数据格式:JSONML 技术原理:通过 MutationObserver API 监听编辑器的 DOM 树变更,生成 JSON 格式的 OP,发送到 ShareDB,更新 JSONML 数据。同时将 OP 发送到其它用户, 将 OP 转化成 DOM 操作方法之后执行
- 47. 多⼈人实时协同 - OP 格式 OP 格式 JSON DOM {p:PATH, li:NEWVALUE} List Insert 插⼊入 Node {p:PATH, ld:OLDVALUE} List Delete 删除 Node {p:PATH, oi:NEWVALUE} Object Insert 增加 Element 属性 {p:PATH, od:OLDVALUE} Object Delete 删除 Element 属性 {p:PATH, si:TEXT} String Insert 插⼊入 Text {p:PATH, sd:TEXT} String Delete 删除 Text
- 48. 多⼈人实时协同 - 时间节点 2019.04:技术选型,开始研发 2019.08:文档编辑器的多人协同上线 2019.10:表格编辑器的多人协同上线(计划)
- 49. 多⼈人实时协同 - 总结 一、L1 传统模式编辑器也可以实现多人实时协同 二、如果其它业务中需要多人实时协同的场景,推荐 ShareDB 三、仅仅完成功能,其实不难,是从 0 到 1 的过程 四、要做成完美,非常难,是从 1 到 100 的过程
- 50.
- 51.