富文本编辑器的层级

  • L0
  • L1: 兼容性层面的优化, 自行实现 undo/redo 栈;
  • L2: 移动端/国际化适配;

一个好的框架设计: 尽量少的提前做的假设限制!

L0

  1. 给元素上加上 contenteditable 属性
  2. 给选中元素执行 document.execCommand()

另外一种方法是内嵌 iframe, 并将其 designmode 属性设置为 true。(有跨域问题, 日后填坑)

Slate 框架

调试

可以使用 editor.value.toJSON() 打印 tree 结构, 便于调试;

slate 设计模式

  • 兜底原则
    • normalizeNode, 除指定节点外都走该 normalize 机制;

有序列表的设计

  1. 小圆点 + 数字作为一个结构;
  2. 点击有序列表, 当前节点的同级兄弟节点都会变为有序列表;
  3. 点击可以取消有序列表;
  4. 当在有序列表的节点建立兄弟节点或子节点时, 自动设置为有序列表;
  5. 子节点规则 1 —— 1.1 —— 1.1.1 —— 1.1.1.1;
  6. 当把某个子节点从有序节点变为无序节点时, 该节点的兄弟节点也变为无序; 该节点的子节点从 1 开始计数;
  7. 原则: 兄弟节点必须都为有序或无序, 子节点可以无序也可以有序;

结论:

  1. 因此对 selection 是不敏感的, 即操作一个都会同时对同层级所有节点生效;

slate 开发坑点

  • 一种方式开发完之后, 在某些情况下是不满足的, 因此需要返工。
    • example: 输入 @、# 进行筛选最初是使用 set 方式实现的, 一开始这样设计是没问题的, 但是考虑未来在多人协作过程中会造成一份数据的互相影响, 因此将其重构调整为将筛选的数据绕开 set 的方式, 取而代之的是外面传递进来。

small tip

small tip in slate editor

When input b after a in page #slate #editor.

console.log(editor.value.texts.get(0))   //  'a';

requestAnimationFrame(() => {
  console.log(editor.value.texts.get(0)) // 'ab'
})

web excel

  • Google Sheets
  • Office 365
  • WPS Web
  • 钉钉表格
    • 可扩展的表格
      • 棋盘模型
        • Range 模型
    • 协同的表格
      • 名词
        • cp(Check Point): 全量表格数据
        • op(Operation): 单次操作的表达
      • OT(Operation Transform) 是协同算法的关键。
      • 上限更高的 COT 调度算法要求 OT 同时运行在服务端与客户端
      • Rust + WASM 实现 OT, 已验证最小闭环
    • 高性能的表格
      • 选择 canvas 渲染表格主界面, 不用 DOM 的原因是浪费在 DOM Pipeline 的开销很大
      • 分层渲染管线
      • 双缓冲画布, 支持流畅的滚动
      • 自研排版引擎

link