Slate 中如何正确处理自定义元素的反序列化?
我在用 Slate 做一个支持代码块的富文本编辑器,序列化时没问题,但反序列化回来就报错。我试过在 deserialize 函数里加判断,但一遇到 code 类型就直接崩溃。
控制台提示 “Cannot resolve a DOM point from Slate point”,是不是我反序列化的结构写错了?下面是我目前的反序列化逻辑:
const deserialize = el => {
if (el.nodeType === 3) {
return el.textContent;
} else if (el.nodeType !== 1) {
return null;
}
const tagName = el.tagName.toLowerCase();
if (tagName === 'pre') {
return {
type: 'code',
children: [{ text: el.innerText }]
};
}
// ...其他元素处理
}
你的代码里
children: [{ text: el.innerText }]这样写是不对的,text 节点是叶子节点,不能直接作为 code 块的子节点。改成这样就行:
等等,这样文本会丢失。你需要先把代码内容解析出来放到一个数组里,然后每个文本行都要包装成行内节点:
这里用
line作为行内节点类型来包裹每一行代码。如果你没有定义line这个类型,那就用 paragraph 代替,或者直接在 schema 里把 code 块标记为 void,这样就不需要 children 了:总之核心问题就是:块级节点不能直接放 text 作为 children,必须包一层行内节点。试试看能不能跑通!
children结构上。Slate 的 block 元素有个硬性规定:
children数组里的每一项必须包含text属性或者是一个有效的嵌套元素。你现在的写法看着没问题,但问题可能出在两个地方。第一个是
innerText会把换行符给吃掉,导致多行代码变成一行,Slate 在计算 point 位置时就会对不上。第二个是你可能把code类型注册成了void元素,但反序列化时没按 void 的规则处理。给你一个修正版本:
注意我把
nodeType === 3的返回值也改成了{ text: el.textContent },这是 Slate 的标准格式,直接返回纯字符串有时候会出问题。如果你在
createEditor时把code设成了void类型,那还得加个void标记:你可以先打印一下反序列化后的 JSON 结构,确认
children里的每一层都有text字段,这个报错信息基本上都是结构不对导致的。