editcontext api 是 chrome 123+ 提供的底层输入控制机制,需弃用 contenteditable,通过监听 input 事件手动处理文本变更、光标、选区及 ime 等,完全自主控制编辑逻辑。

EditContext API 是 Chrome 123+ 引入的底层输入控制机制,它不替代 ContentEditable,而是让开发者在浏览器原生输入事件(如按键、粘贴、IME 输入、语音转文字)真正触达编辑区域前,就获得拦截、解析、转换和手动提交的能力。它适用于需要完全自定义文本行为的场景——比如语法高亮实时渲染、结构化文档(如 Notion 风格块)、数学公式嵌入、协作光标同步、或绕过 ContentEditable 的 DOM 污染与不可预测性。
核心前提:脱离 ContentEditable,接管输入生命周期
使用 EditContext 必须放弃 contenteditable="true"。取而代之的是一个普通元素(如 <div>),通过 <code>element.editContext = new EditContext() 激活输入能力。此时该元素成为“可编辑目标”,但所有文本变更不再自动反映在 DOM 中——你需自行维护内部状态(如字符串、AST 或块模型),并在合适时机调用 editContext.updateComposition() 或 editContext.replaceText() 主动写入。
- 首次聚焦时需显式调用
editContext.setCaretRange(range)设置光标位置,否则光标不可见 - 键盘输入默认被静默丢弃,必须监听
input事件(类型为"insertText","deleteContentBackward"等)并手动响应 - 粘贴、拖放、IME 组合、语音输入等均触发对应
input事件,且附带原始数据(如dataTransfer、data字符串、range位置)
关键操作:从事件到可控更新
每个 input 事件携带 inputType、data、targetRange 和 getTargetRanges()。你需要基于这些信息决定如何修改内部状态,并用 EditContext 方法同步视觉反馈:
-
插入纯文本:监听
inputType === "insertText",用editContext.replaceText(data, targetRange)写入;若需保留格式(如加粗段落中插入),先解析当前格式上下文,再构造带标记的文本片段 -
删除逻辑:区分
"deleteContentBackward"(退格)、"deleteContentForward"(Delete)、"deleteByCut"(剪切);根据targetRange计算应删字符范围,更新模型后调用replaceText("", range) -
处理粘贴:监听
inputType === "insertFromPaste",通过event.dataTransfer?.getData("text/plain")或 HTML 获取内容,按需清洗/转换(如移除富文本样式、解析 Markdown 表格),再用replaceText()插入 -
IME 与组合输入:监听
"compositionStart"/"compositionUpdate"/"compositionEnd",用updateComposition()动态渲染候选字,结束时用replaceText()提交最终文本
光标与选区:完全自主控制
EditContext 不提供自动光标渲染。你必须监听 selectionchange(或用 document.getSelection() 主动轮询),结合内部状态计算光标应处的视觉位置(如某段第 5 个字符后),再调用 editContext.setCaretRange({start: offset, end: offset})。选区同理:当用户拖选时,targetRange 在 input 事件中给出逻辑范围,你需将其映射到你的数据模型索引,并用 setSelectionRange() 同步高亮显示(通常配合 CSS ::selection 或绝对定位覆盖层)。
- 光标闪烁需自行用
setInterval切换caret-color或覆盖层 visibility - 多段落/块编辑器中,“光标位于块末尾”需判断是否应自动创建新块,这逻辑完全由你实现
- 键盘方向键(ArrowLeft/Right/Up/Down)需监听
keydown,阻止默认行为,按模型结构计算新光标位置,再调用setCaretRange()
注意事项与兼容性边界
EditContext 目前仅 Chromium 支持(Chrome ≥123,Edge ≥123),无 Polyfill。生产环境需降级策略:
- 检测
"EditContext" in window,不支持时回退至 ContentEditable +beforeinput(部分能力受限) - 避免依赖
execCommand或document.execCommand,它们与 EditContext 冲突 - 无障碍支持需额外工作:手动设置
role="textbox"、aria-multiline="true"、aria-valuetext,并响应aria-activedescendant变化 - 性能敏感:每次
replaceText()都触发重排,高频输入(如 IME 连续上屏)建议节流或批量合并操作










