Lexical 简介

lexical
Created 2/2/2023
Updated 2/3/2023

Lexical 简介

Lexical 是一个用于构建网页文本编辑器的 JavaScript 工具库,它是零依赖 dependency-free 并由多个核心模块组成,所以拓展性和适用性都很好。

它基于 contentEditable 的 DOM 元素(为用户提供 UI 交互),但是编辑器的具体行为逻辑则通过各种自定义的 API 实现(而不是原生的 DOM 行为),这样可以让编辑器在各种边缘条件/场景更为可控。

提示

目前 Lexical 只能用于 Web 平台,但是也有「跨平台」的计划:

根据这个推文介绍,目前 Meta 使用原生的 TextKit 来开发 iOS 平台的 Lexical,提供类似的 API,值得持续关注

推荐

有一些关于 Lexical 的资源可以一看:

以下是 Lexical 中所涉及的一些核心思想

Editor 实例

Editor 实例就是编辑器的核心,它接受并处理用户交互指令,并与一个 contentEditable 元素绑定,控制该 DOM 的 UI 如何更新。

Editor State

Editor State 编辑器状态是指用于表示编辑器当前状态的一份数据

说明

由于 Lexical 采用抽象的数据模型 data model 来描述(编辑器所绑定的 contentEditable 的)DOM 外观及其行为,所以可以通过一份数据来记录编辑器的状态

Editor State 编辑器状态是可以 serializable 序列化(支持 HTML 或 JSON 格式)和 deserialize 反序列化,便于将编辑器的状态/内容进行持久化保存。

它包含两个部分:

  • 节点树
  • 选择范围

Editor State 编辑器状态示意图
Editor State 编辑器状态示意图

注意

Editor State 编辑器状态是 immutable 不可变的,一旦创建就是不能再修改。当编辑器的内容需要改变时,则需要调用相应的方法,创建一个新的 Editor State 编辑器状态,即用一份新的数据(而不是直接修改原有的那一份数据)来表示当前编辑器新的内容

Editor 更新

前面提到 Editor State 编辑器状态是一个 immutable 不可变的数据,所以在变动编辑器的内容时,需要调用相应的方法,这个过程就是 Editor Update 编辑器更新。

说明

通过 editor.update(() => {...}) 方法来执行编辑器更新,也只有在这个回调函数里才能够调用 Lexical 所提供的一些以 $ 为前缀的函数,用于触发页面的 DOM 变化

响应性

除了通过 editor.update() 的方法触发编辑器的更新,Lexical 还提供了多种 hook 时机对编辑器的各种变更做出响应(进行「二次」更新),让编辑器的交互更灵活多变,包括 listener 侦听器、node transform 节点转换、command dispatch 指令分发:

  • listener 侦听器:监听编辑器的某个行为,当这个行为触发时,就以执行相应的响应操作
  • node transform 节点转换:当某个节点符合特定的规则时,会触发相应的转换/操作
    提示

    可以理解为是某个类型的节点所特有的侦听器

  • command dispatch 指令分发:指令就像 DOM 的原生事件一样,当指令被分发时,预先注册到编辑器上的相应的回调函数就会被调用
    说明

    最常见的一个应用场景是将指令绑定到键盘按键,这样可以实现通过快捷键操作编辑器。

    在编辑器上为指令注册的响应函数是可以设置优先级的,在指令分发时这些回调函数会依据优先级依次被调用。

    而且指令分发像 DOM 原生事件一样,可以取消 propagation 传播,这样就可以实现优先级较高的函数被调用,而优先级较低的回调函数就不被调用。

说明

listener 侦听器、node transform 节点转换、command dispatch 指令分发,它们都是通过一些以 register 为前缀的方法注册到编辑器上来实现的。

而且这些方法的返回值都是一个 unsubscribe 取消注册的方法,可以在不需要时取消它们。

DOM Reconciler

当 Editor 更新时 Lexical 会根据 current(当前的)和 pending(待应用的)Editor State 的 diff 差异,调用内置 DOM Reconciler 协调器,更新页面上必要的元素。


Copyright © 2025 Ben

Theme BlogiNote

Icons from Icônes