# 编辑器
Slate
编辑器所有的行为,内容,和状态都会汇总到到一个顶级的 Editor
对象中。它的接口是这样的:
interface Editor {
children: Node[]
selection: Range | null
operations: Operation[]
marks: Record<string, any> | null
[key: string]: unknown
// Schema-specific node behaviors.
isInline: (element: Element) => boolean
isVoid: (element: Element) => boolean
normalizeNode: (entry: NodeEntry) => void
onChange: () => void
// Overrideable core actions.
addMark: (key: string, value: any) => void
apply: (operation: Operation) => void
deleteBackward: (unit: 'character' | 'word' | 'line' | 'block') => void
deleteForward: (unit: 'character' | 'word' | 'line' | 'block') => void
deleteFragment: () => void
insertBreak: () => void
insertFragment: (fragment: Node[]) => void
insertNode: (node: Node) => void
insertText: (text: string) => void
removeMark: (key: string) => void
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
看起来比其他接口要稍微复杂一点,因为它包含了所有你定义的顶级函数和自定义域的操作。
children
属性包含了组成编辑器内容的节点的文档树。
selection
属性包含了用户当前选择的文档片段 (如果有的话)。
operations
属性包含了所有自上次更改以来所应用的操作。(Slate
在事件循环两个 tick
之间的分批操作`
marks
属性存储了光标附带的格式,该格式将应用到插入的文本上。
# 重写行为(Overriding Behaviors)
在之前的指南中我们已经暗示了这一点,你可以通过重写编辑器的函数属性来重写它的任何行为。
比如,如果你想定义链接元素是一个行内元素:
const { isInline } = editor
editor.isInline = element => {
return element.type === 'link' ? true : isInline(element)
}
1
2
3
4
5
2
3
4
5
或者你可能想要重写 insertText
行为来 “链接” 地址:
const { insertText } = editor
editor.insertText = text => {
if (isUrl(text)) {
// ...
return
}
insertText(text)
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
或者你甚至想要自定义“规范”,用来确保链接遵从某些约束:
const { normalizeNode } = editor
editor.normalizeNode = entry => {
const [node, path] = entry
if (Element.isElement(node) && node.type === 'link') {
// ...
return
}
normalizeNode(entry)
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
无论你怎样重写行为,确保调用默认的函数作为后备行为。除非你真的想要完全移除默认行为。(这不是一个好主意!)
# 辅助函数(Helper Functions)
Editor
接口和所有的 Slate
接口一样,暴露了一些有用的辅助函数用来实现某些行为。比如说:
// 获取路径上指定节点的起点
const point = Editor.start(editor, [0, 0])
// 从一个选择范围(range)获取文档片段
const fragment = Editor.fragment(editor, range)
1
2
3
4
5
2
3
4
5
还有一些基于迭代的辅助函数,比如:
// 迭代选择范围(range)的每一个节点
for (const [node, path] of Editor.nodes(editor, { at: range })) {
// ...
}
// 迭代当前文档片段(selection)的文本节点的每一点(point)
for (const [point] of Editor.positions(editor)) {
// ...
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
← 操作(Operations) 插件 →