编辑器
Slate 编辑器所有的行为,内容,和状态都会汇总到到一个顶级的 Editor 对象中。它的接口是这样的:
interface Editor {children: Node[]selection: Range | nulloperations: Operation[]marks: Record<string, any> | null[key: string]: any// 自定义模式(schema)的节点行为isInline: (element: Element) => booleanisVoid: (element: Element) => booleannormalizeNode: (entry: NodeEntry) => voidonChange: () => void// 可重写的核心行为。addMark: (key: string, value: any) => voidapply: (operation: Operation) => voiddeleteBackward: (unit: 'character' | 'word' | 'line' | 'block') => voiddeleteForward: (unit: 'character' | 'word' | 'line' | 'block') => voiddeleteFragment: () => voidinsertBreak: () => voidinsertFragment: (fragment: Node[]) => voidinsertNode: (node: Node) => voidinsertText: (text: string) => voidremoveMark: (key: string) => void}
看起来比其他接口要稍微复杂一点,因为它包含了所有你定义的顶级函数和自定义域的操作。
children 属性包含了组成编辑器内容的节点的文档树。
Tselection 属性包含了用户当前选择的文档片段(如果有的话)。
operations 属性包含了所有自上次更改以来所应用的操作。(Slate 在事件循环两个tick之间的分批操作)
marks 属性存储了光标附带的格式,该格式将应用到插入的文本上。
重写行为
在之前的指南中我们已经暗示了这一点,你可以通过重写编辑器的函数属性来重写它的任何行为。
比如,如果你想定义链接元素是一个行内元素:
const { isInline } = editoreditor.isInline = element => {return element.type === 'link' ? true : isInline(element)}
或者你可能想要重写 insertText 行为来“链接”地址:
const { insertText } = editoreditor.insertText = text => {if (isUrl(text) {// ...return}insertText(text)}
或者你甚至想要自定义“规范”,用来确保链接遵从某些约束:
const { normalizeNode } = editoreditor.normalizeNode = entry => {const [node, path] = entryif (Element.isElement(node) && node.type === 'link') {// ...return}normalizeNode(entry)}
无论你怎样重写行为,确保调用默认的函数作为后备行为。除非你真的想要完全移除默认行为。(这不是一个好主意!)
辅助函数
Editor 接口和所有的 Slate 接口一样,暴露了一些有用的辅助函数用来实现某些行为。比如说:
// 获取路径上指定节点的起点。const point = Editor.start(editor, [0, 0])// 从一个选择范围(range)获取文档片段。const fragment = Editor.fragment(editor, range)
还有一些基于迭代的辅助函数,比如:
// 迭代选择范围(range)的每一个节点。for (const [node, path] of Editor.nodes(editor, { at: range })) {// ...}// 迭代当前文档片段(selection)的文本节点的每一点(point)。for (const [point] of Editor.positions(editor)) {// ...}
