Slate 中如何正确处理自定义节点的反序列化?

丽苹 阅读 53

我在用 Slate 做富文本编辑器,想支持自定义的 block 节点,比如代码块。但把 HTML 字符串转回 editor value 时,自定义节点总是变成默认的 paragraph,试了在 deserialize 函数里加判断也不生效。

我参考文档写了类似这样的逻辑:

const deserialize = el => {
  if (el.tagName.toLowerCase() === 'pre') {
    return { type: 'code', children: [{ text: el.innerText }] };
  }
  // ...其他逻辑
}

但实际解析出来的节点还是 { type: 'paragraph', ... },是不是哪里漏了配置?

我来解答 赞 6 收藏
二维码
手机扫码查看
1 条解答
迷人的婷婷
这个问题我之前也碰到过,其实 Slate 的 deserialize 需要返回完整的节点对象,光有 type 不够,还得加上 object: 'block'

你的代码大概是这样写的对吧:

const deserialize = el => {
if (el.tagName.toLowerCase() === 'pre') {
return { type: 'code', children: [{ text: el.innerText }] };
}
}


问题在于缺少 object 字段,Slate 不知道你要创建什么类型的节点。改成这样试试:

const deserialize = el => {
if (el.tagName.toLowerCase() === 'pre') {
return {
object: 'block',
type: 'code',
children: [{ text: el.innerText }]
};
}
// 其他逻辑
}


然后关键是你得把这个 deserialize 注册到 editor 上。Slate 用的是 plugins 机制,你得覆盖 editor 的 deserialize 方法:

const CodeBlockPlugin = {
deserialize: (el, editor) => {
if (el.tagName.toLowerCase() === 'pre') {
return {
object: 'block',
type: 'code',
children: [{ text: el.innerText }]
};
}
}
};

const editor = withReact(createEditor());
const plugins = [CodeBlockPlugin];


或者更直接的方式,在初始化 editor 时包装一下:

const withCodeBlock = editor => {
const { deserialize } = editor;

editor.deserialize = el => {
if (el.tagName.toLowerCase() === 'pre') {
return {
object: 'block',
type: 'code',
children: [{ text: el.innerText }]
};
}
return deserialize(el);
};

return editor;
};

const editor = withCodeBlock(withReact(createEditor()));


还有一点要注意,你的自定义节点需要在 renderElement 里正确处理,确保 type: 'code' 对应的是代码块组件:

const renderElement = useCallback(props => {
switch (props.element.type) {
case 'code':
return <pre {...props.attributes}>{props.children}</pre>;
default:
return <p {...props.attributes}>{props.children}</p>;
}
}, []);


这几个地方都对上了基本就没问题了。你先试试加上 object: 'block' 这行,看看能不能work。
点赞
2026-03-17 21:02