高频问答与回答框架
1. Slate 和 ProseMirror / Draft.js 的核心差异是什么?
可答要点
- Slate 是 schema-less core + plugin 扩展,不把业务 schema 写死
- 所有变更都数据化为 operation,天然利于 history/协作
- React 集成深,但 DOM 兼容问题也更直接暴露
2. Slate 为什么强调 operation,而不是直接改节点?
可答要点
- operation 是统一“变更事实”格式
- 便于回放、逆运算、网络传输
- 让 undo/redo、协作、调试围绕同一抽象完成
可引用:packages/slate/src/interfaces/operation.ts
3. Transforms 和 Editor 方法区别是什么?
可答要点
- 都是高层语义 API
- 本质都会走到
editor.apply(op)(可能一个 API 触发多个 op) Transforms更偏批量/结构化操作;Editor.*更偏用户动作语义
4. Normalization 是什么时候触发的?
可答要点
- 每次
apply(op)后会进入 normalize 流程 - dirty path 驱动多轮修复
- 可用
Editor.withoutNormalizing延迟批量修复
可引用:core/apply.ts、editor/normalize.ts
5. withoutNormalizing 是不是会跳过 normalize?
标准回答
不是。它是“延迟执行”,不是“永久关闭”。
回调结束后会统一 normalize。
(很多人会答错,能区分这一点会很加分)
6. Slate 为什么把 value 变成 initialValue 语义?
可答要点
- 受控模式在复杂输入时序下容易出现状态错序覆盖
- 官方逐步把
<Slate />定位为更偏 uncontrolled 的容器 - 社区对 controlled 诉求仍强,相关 issue 长期存在
证据:
- PR #4540 / PR #4922
- issue #4992 / #5281 / #4612
7. Slate 如何处理 IME(中文输入法)问题?
可答要点
- 原生
beforeinput+ composition 状态机 - Android 走专门 input manager
- 必要时 DOM 与 Slate 选区双向校准与恢复
证据:
editable.tsx+android-input-manager.ts- issue #4400 / #5023
8. undo/redo 的粒度如何控制?
可答要点
- 默认连续文本输入会合批
set_selection不记录历史- 复杂命令要用
withNewBatch/withMerging/withoutSaving
证据:packages/slate-history/src/with-history.ts
9. Cannot resolve a Slate point from DOM point 常见原因?
可答要点
- DOM 映射缓存与渲染时序失步
- 自定义 void/non-editable 节点 DOM 结构不符合预期
- 选区落到非可编辑目标或异常 shadow root 场景
排查顺序:
- 校验
renderElement/renderLeaf的 data-slate 属性结构 - 看 selection 监听和异步 setState 时序
- 检查是否在 onChange 过早调用
findPath
10. 大文档性能怎么优化?
可答要点
- selector 细粒度订阅(
useSlateSelector) - 降低不必要 rerender(memo/equalityFn)
- 超长列表启用 chunking(
getChunkSize) - 避免高频全量遍历节点
11. 可延伸讨论(高级加分)
- 你们当前最痛的是输入法兼容、协作冲突还是大文档性能?
- 历史撤销粒度是否有产品约束(按字符/按动作/按命令)?
- 是否有跨端(WebView/移动浏览器)要求?
这能自然把你引到 Slate 的强项话题上。