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

上官世暄 阅读 4

我在用 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 }]
    };
  }

  // ...其他元素处理
}
我来解答 赞 4 收藏
二维码
手机扫码查看
1 条解答
公孙紫瑶
这个报错我之前也踩过坑,问题出在你的 children 结构上。

Slate 的 block 元素有个硬性规定:children 数组里的每一项必须包含 text 属性或者是一个有效的嵌套元素。你现在的写法看着没问题,但问题可能出在两个地方。

第一个是 innerText 会把换行符给吃掉,导致多行代码变成一行,Slate 在计算 point 位置时就会对不上。第二个是你可能把 code 类型注册成了 void 元素,但反序列化时没按 void 的规则处理。

给你一个修正版本:

const deserialize = el => {
if (el.nodeType === 3) {
return { text: el.textContent };
} else if (el.nodeType !== 1) {
return null;
}

const tagName = el.tagName.toLowerCase();

if (tagName === 'pre') {
// 用 textContent 而不是 innerText,保留换行符
const codeEl = el.querySelector('code') || el;
return {
type: 'code',
children: [{ text: codeEl.textContent || '' }],
};
}

// 其他元素处理...
}


注意我把 nodeType === 3 的返回值也改成了 { text: el.textContent },这是 Slate 的标准格式,直接返回纯字符串有时候会出问题。

如果你在 createEditor 时把 code 设成了 void 类型,那还得加个 void 标记:

if (tagName === 'pre') {
const codeEl = el.querySelector('code') || el;
return {
type: 'code',
void: true, // 如果你的 schema 里 code 是 void 类型
children: [{ text: '' }], // void 元素 children 必须是空文本
};
}


你可以先打印一下反序列化后的 JSON 结构,确认 children 里的每一层都有 text 字段,这个报错信息基本上都是结构不对导致的。
点赞 1
2026-03-01 13:00