Prosemirror核心概念

Nov. 26 · 3min

个人觉得 prosemirror 的概念还是比较难理解的,在深入源码之前,有必要对这些概念有一个大致的了解。

schema

shema 用于定义编辑器的文档模型,一个基本的 schema 定义如下:

import { Schema } from "prosemirror-model";

// schema由nodes和marks组成
const exampleSchema = new Schema({
  nodes: {
    // doc必须定义
    doc: {
      content: "paragraph+",
    },
    paragraph: {
      content: "text*",
      group: "block",
      // DOM的解析规则。
      // 这条规则的意思是:如果遇到p标签,就解析为paragraph节点
      parseDOM: [{ tag: "p" }],
      // 转换为DOM的规则。
      // 这条规则的意思是:如果遇到paragraph节点,就转换为p标签,0叫做“洞”(hole),表示可以插入内容
      toDOM(node) {
        return ["p", 0];
      },
    },
    text: {},
  },
  marks: {
    strong: {
      parseDOM: [{ tag: "strong" }],
      toDOM() {
        return ["strong"];
      },
    },
  },
});

selection

prosemirror 的选区系统。

new Selection(
  $anchor: ResolvedPos,
  $head: ResolvedPos,
  ranges: readonly SelectionRange[]
)

slice

new Slice(
  content: Fragment,
  openStart: number, // slice开头未闭合的标签深度
  openEnd: number // slice结尾未闭合的标签深度
)

transactions

prosemirror 借鉴了 redux 的思想,不直接修改 state,而是在旧的 state 的基础上,通过 dispatch(transaction)生成新的 state。

steps

step 是文档修改的最小单位,一个 tranaction 可以包含多个 steps,保存在 transaction 的 steps 属性中。

mapping

文档经过一系列 steps 修改后,可以通过 mapping 将旧的位置映射到新的位置。

commands

编辑器命令,可以通过 keymap 建立键盘快捷键与命令之间的映射。Command 函数接收 state 和可选的 dispatch 作为参数,返回 boolean。

plugins

插件系统用于为编辑器添加额外的功能,一个简单的插件定义如下:

const myPlugin = new Plugin({
  // 插件名称
  name: "myPlugin",
  // 插件初始化函数
  init() {
    // 插件初始化时,将插件的state初始化为一个空对象
    this.state = {};
  },
  // 插件的状态更新函数
  apply(tr, state) {
    // 根据tr和state更新插件state
    if (tr.docChanged) {
      this.state = {...this.state,...state.toJSON() };
    } else {
      this.state = {...this.state };
    }
}
> cd ..