Copyright © 2025 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
本规范定义了文本及相关输入的事件扩展,以便在文本编辑器应用程序和其他处理文本输入及文本格式化的应用程序中,监控和操作默认的浏览器行为。本规范基于UI事件规范 [UI-EVENTS]。
本节描述了本文件在发布时的状态。当前 W3C 出版物列表以及本技术报告的最新修订版可在 W3C 标准与草案索引中找到。
输入事件规范 第2级 取代了输入事件的第一个版本 [INPUT-EVENTS],并包含:
本文件由 Web 编辑工作组 作为工作草案发布,使用了推荐轨道。
发布为工作草案并不意味着 W3C 及其成员的认可。
本文档为草案,可能随时被其他文档更新、替换或废弃。将本文件作为除“进行中工作”之外的引用是不合适的。
本文档由一组遵循 W3C 专利政策 的成员编写。 W3C 维护着一个 有关本小组成果的公开专利披露列表; 该页面还包括专利披露说明。任何个人若实际知晓某项专利并认为其包含 必要权利要求(Essential Claim(s)), 必须根据 W3C 专利政策第 6 节 披露相关信息。
本文件受 2023年11月3日 W3C 流程文件 的约束。
本文档描述了与编辑相关的两个事件的扩展 - input 和 beforeinput,这些事件在 UI 事件规范中进行了描述 [UI-EVENTS]。这些事件的目的是允许开发者理解和/或覆盖编辑行为的默认处理,编辑操作在执行前或执行后。
除标记为非规范性的章节外,本规范中的所有作者指南、图表、示例和注释均为非规范性内容。其他所有内容均为规范性内容。
本文档中的关键词 MAY、MUST 和 MUST NOT 应按照 BCP 14 [RFC2119] [RFC8174] 的说明进行解释,仅当这些词以如上所示全部大写形式出现时,才按上述定义解释。
此定义为非规范性内容。
杀死缓冲区 是一个与剪贴板分开的内存存储区域,用于暂存通过特定删除命令删除的富文本内容。用户可以通过表达“提取杀死缓冲区”的意图,将杀死缓冲区中的内容替换当前选中的内容。本节为非规范性内容。
创建一个基于Web的文本编辑器需要在浏览器代码之上编写大量的JavaScript,部分原因是:
本规范旨在通过提供一种简单的方法,允许Web开发者通过 beforeinput 事件覆盖浏览器对所有与文本编辑相关的用户输入的处理,并通过 input 事件监控浏览器因用户输入而对DOM的更改,从而缓解这一问题。
本节为非规范性内容。
输入事件在用户尝试编辑标记之前(beforeinput事件)和之后(input事件)发送。这包括内容的插入和删除,以及格式更改。
输入事件会在作为 编辑主机(editing hosts)
的元素上分派,包括设置了
contenteditable
属性的元素、textarea
元素,以及允许文本输入的
input
元素。
WebIDLpartial interface InputEvent {
readonly attribute DataTransfer? dataTransfer
;
sequence<StaticRange> getTargetRanges
();
};
partial dictionary InputEventInit {
DataTransfer? dataTransfer
= null;
sequence<StaticRange> targetRanges
= [];
};
inputType
、dataTransfer
和
targetRanges
这三个 InputEventInit
的属性用于初始化 InputEvent
对象的对应属性。
本节为非规范性内容。
下表总结了data
和dataTransfer
属性何时包含内容、何时为null,以及getTargetRanges()
方法何时返回空数组或非空数组,具体取决于inputType
。
编辑主机 | inputType | data | dataTransfer | getTargetRanges() |
---|---|---|---|---|
Contenteditable |
"insertText" ,
"insertCompositionText" ,
"formatSetBlockTextDirection" ,
"formatSetInlineTextDirection" ,
"formatBackColor" ,
"formatFontColor" ,
"formatFontName" , "insertLink"
|
Yes | null | 非空数组 |
Contenteditable |
"insertFromPaste" ,
"insertFromPasteAsQuotation" ,
"insertFromDrop" ,
"insertReplacementText" ,
"insertFromYank"
|
null | Yes | 非空数组 |
<textarea> , <input type="text">
|
"insertText" ,
"insertCompositionText" ,
"insertFromPaste" ,
"insertFromPasteAsQuotation" ,
"insertFromDrop" ,
"insertReplacementText" ,
"insertFromYank" ,
"formatSetBlockTextDirection" ,
"formatSetInlineTextDirection" ,
"formatBackColor" ,
"formatFontColor" ,
"formatFontName" , "insertLink"
|
Yes | null | 空数组 |
所有 |
"historyUndo" , "historyRedo"
|
null | null | 空数组 |
Contenteditable | 所有剩余 | null | null | 非空数组 |
<textarea> , <input type="text">
|
所有剩余 | null | null | 空数组 |
beforeinput事件是否可取消取决于inputType。
inputType的选择取决于用户的意图表达,编辑是否在IME组合过程中进行,以及选择的状态。
本规范将inputType值定义为下表中的inputType列中的值。
inputType | 用户的意图表达 | IME组合的一部分 | beforeinput是否可取消 | 选择的状态 |
---|---|---|---|---|
"insertText"
|
插入键入的纯文本 | 否 | 是 | 任何 |
"insertReplacementText"
|
通过拼写检查器、自动更正、书写建议或类似方式插入或替换现有内容 | 否 | 是 | 任何 |
"insertLineBreak"
|
插入换行符 | 否 | 是 | 任何 |
"insertParagraph"
|
插入段落符 | 否 | 是 | 任何 |
"insertOrderedList"
|
插入编号列表 | 否 | 是 | 任何 |
"insertUnorderedList"
|
插入项目符号列表 | 否 | 是 | 任何 |
"insertHorizontalRule"
|
插入水平线 | 否 | 是 | 任何 |
"insertFromYank"
|
用存储在kill buffer中的内容替换当前选择 | 否 | 是 | 任何 |
"insertFromDrop"
|
通过拖放插入内容 | 否 | 是 | 任何 |
"insertFromPaste"
|
从剪贴板粘贴内容或从客户端提供的图像库粘贴图像 | 否 | 是 | 任何 |
"insertFromPasteAsQuotation"
|
作为引用从剪贴板粘贴内容 | 否 | 是 | 任何 |
"insertTranspose"
|
调换最后输入的两个字素簇(grapheme cluster)的顺序。 | 否 | 是 | 任何 |
"insertCompositionText"
|
替换当前组合字符串 | 是 | 否 | 任何 |
"insertLink"
|
插入链接 | 否 | 是 | 任何 |
"deleteWordBackward"
|
删除光标位置前的单词 | 否 | 是 | 折叠 |
"deleteWordForward"
|
删除光标位置后的单词 | 否 | 是 | 折叠 |
"deleteSoftLineBackward"
|
从光标位置删除到最近的视觉换行符之前 | 否 | 是 | 折叠 |
"deleteSoftLineForward"
|
从光标位置删除到最近的视觉换行符之后 | 否 | 是 | 折叠 |
"deleteEntireSoftLine"
|
从光标位置之前的最近视觉换行符删除到光标位置之后的最近视觉换行符 | 否 | 是 | 折叠 |
"deleteHardLineBackward"
|
从光标位置删除到块元素的最近开头或
br
元素之前
|
否 | 是 | 折叠 |
"deleteHardLineForward"
|
从光标位置删除到块元素的最近结尾或
br
元素之后
|
否 | 是 | 折叠 |
"deleteByDrag"
|
通过拖动从DOM中删除内容 | 否 | 是 | 任何 |
"deleteByCut"
|
作为剪切的一部分删除当前选择 | 否 | 是 | 任何 |
"deleteContent"
|
删除选择而不指定删除的方向,并且此意图不被另一个inputType涵盖 | 否 | 是 | 未折叠 |
"deleteContentBackward"
|
删除光标位置前的内容,并且此意图不被另一个inputType涵盖,或者删除选择,选择在删除后折叠到其开始位置 | 否 | 是 | 任何 |
"deleteContentForward"
|
删除光标位置后的内容,并且此意图不被另一个inputType涵盖,或者删除选择,选择在删除后折叠到其结束位置 | 否 | 是 | 任何 |
"historyUndo"
|
撤销最后的编辑操作 | 否 | 是 | 任何 |
"historyRedo"
|
重做最后撤销的编辑操作 | 否 | 是 | 任何 |
"formatBold"
|
启动粗体文本 | 否 | 是 | 任何 |
"formatItalic"
|
启动斜体文本 | 否 | 是 | 任何 |
"formatUnderline"
|
启动下划线文本 | 否 | 是 | 任何 |
"formatStrikeThrough"
|
启动删除线文本 | 否 | 是 | 任何 |
"formatSuperscript"
|
启动上标文本 | 否 | 是 | 任何 |
"formatSubscript"
|
启动下标文本 | 否 | 是 | 任何 |
"formatJustifyFull"
|
将当前选择完全对齐 | 否 | 是 | 任何 |
"formatJustifyCenter"
|
将当前选择居中对齐 | 否 | 是 | 任何 |
"formatJustifyRight"
|
将当前选择右对齐 | 否 | 是 | 任何 |
"formatJustifyLeft"
|
将当前选择左对齐 | 否 | 是 | 任何 |
"formatIndent"
|
缩进当前选择 | 否 | 是 | 任何 |
"formatOutdent"
|
减少当前选择的缩进 | 否 | 是 | 任何 |
"formatRemove"
|
删除当前选择的所有格式 | 否 | 是 | 任何 |
"formatSetBlockTextDirection"
|
设置文本块方向 | 否 | 是 | 任何 |
"formatSetInlineTextDirection"
|
设置文本行方向 | 否 | 是 | 任何 |
"formatBackColor"
|
更改背景颜色 | 否 | 是 | 任何 |
"formatFontColor"
|
更改字体颜色 | 否 | 是 | 任何 |
"formatFontName"
|
更改字体家族 | 否 | 是 | 任何 |
inputTypes
的存在并不意味着所有实现都必须支持全部这些类型。但如果某个浏览器支持某种可能导致 DOM 发生变化的编辑操作,则它 MUST 分派 相应的
beforeinput
和 input
事件。
"deleteContentBackward"
将用于用户请求在文本节点内删除文本时,以及当用户表示删除更复杂的元素或在光标位于文本节点开头时合并段落时。
"deleteContentForward"
将用于用户请求在文本节点内删除文本时,以及当用户表示删除更复杂的元素或在光标位于文本节点末尾时合并段落时。
data
保存与要添加到文档中的内容相关的纯文本数据。
inputType | 编辑主机 | data |
---|---|---|
"insertText" 或
"insertCompositionText"
|
任意 | 要插入的纯文本字符串 |
"insertFromPaste" ,
"insertFromPasteAsQuotation" ,
"insertFromDrop" ,
"insertTranspose" ,
"insertReplacementText" 或
"insertFromYank"
|
input
或
textarea
|
要插入的纯文本字符串 |
"formatSetInlineTextDirection" 或
"formatSetBlockTextDirection"
|
任意 |
"ltr" ,"rtl" ,"auto"
或"null"
|
"formatBackColor" 或
"formatFontColor"
|
任意 | 包含序列化CSS组件值的字符串 [CSSOM] 用于建议的颜色 |
"formatFontName"
|
任意 | 提议的字体家族CSS属性值 |
"insertLink"
|
任意 | 提议的链接URL |
所有其他 | 任意 | null |
dataTransfer
属性在有相关数据时,将关于富文本和纯文本数据的信息保存在
DataTransfer
对象中,用于从文档提取或向文档添加数据。
inputType | 编辑主机 | dataTransfer |
---|---|---|
"insertFromPaste" ,
"insertFromPasteAsQuotation" ,
"insertFromDrop" ,
"insertTranspose" ,
"insertReplacementText" 或
"insertFromYank"
|
contenteditable
|
预先填充的 DataTransfer
对象,具体如下:
|
所有其他 | 任意 | null |
getTargetRanges()
返回一个 StaticRange
数组,表示如果事件未被取消,将要被修改的内容。返回的 StaticRange MUST 仅覆盖浏览器通常会替换的 码点(code points),即使它们只是 字素簇(grapheme cluster) 的一部分。
本注释不具规范性。
根据不同的书写系统和平台,在文本节点中使用折叠选区向前或向后删除时,可能会影响一个或多个码点,或整个字素簇(grapheme cluster)。例如,在包含“café”的文本节点中向后删除,可能会删除重音符号,也可能会直接删除整个“é”字符,这取决于书写系统和平台。inputType | 编辑主机 |
getTargetRanges() 的响应
|
---|---|---|
"historyUndo" 或 "historyRedo"
|
任意 | 空数组 |
其他所有 |
contenteditable
|
一个包含 StaticRanges 的数组 [DOM] 与事件相关联 |
其他所有 |
input
或
textarea
|
空数组 |
返回值,除非 inputType 为 "historyUndo"
或 "historyRedo"
,或 编辑主机(editing
host) 不是 contenteditable 元素,此时将返回一个空数组。
beforeinput
类型 |
beforeinput
|
---|---|
接口 |
InputEvent
|
同步 / 异步 | 同步 |
冒泡 | 是 |
受信目标 |
任何作为 Element 的 编辑主机(editing
host)。
|
默认操作 [UI-EVENTS] |
|
上下文 (受信事件) |
|
用户代理(user agent) MUST 在用户尝试在 contenteditable 元素中输入时 分派 此事件。这并不一定意味着 用户代理会随即更新 DOM。
input
类型 | input |
---|---|
接口 | InputEvent |
同步/异步 | 同步 |
冒泡 | 是 |
可信目标 | 任何启用了 contenteditable 属性的 Element 。 |
默认操作 [UI-EVENTS] | 无 |
上下文 (可信事件) |
|
用户代理(user agent) MUST 应在由于用户明确意图更改文档内容且浏览器已处理该操作后、DOM 被更新后立即 分派此事件。如果浏览器未进行任何 DOM 更改,无论是因为编辑主机为 EditContext 编辑主机(其不会自动更改 DOM),还是因为 用户代理认定无需更改 DOM,则用户代理 MUST NOT 分���此事件。
合成的开始通过调度 compositionstart 事件标记。
在合成会话期间,每当文本合成系统更新其活动文本段落时,都会调度 compositionupdate 事件。
在每个 compositionupdate
事件之后,会调度一对 beforeinput
和 input
事件。
beforeinput
和 input
事件:
inputType
属性且值为
"insertCompositionText"
data
属性等于 compositionupdate 事件的 data
targetRange
包围了合成的活动文本段落
活动文本段落的 DOM 内容在调度 beforeinput
事件后,input
事件之前更新。
合成会话的结束通过调度 compositionend 事件标记。
当调度 "insertFromPaste"
beforeinput
事件时,它 必须 之前已经调度了 paste 事件。[CLIPBOARD-APIS]
本节不是规范性的。
除了现有事件(如 keydown
和
keypress
[UI-EVENTS]
事件)中已存在的
浏览器指纹识别
[fingerprinting-guidance]
技术外,此功能没有已知的安全或隐私影响。
如果此功能替换现有事件,它 可能 导致可用的 指纹识别 技术减少,因为记录的是用户的意图,而不是他们使用的特定硬件类型来 表达 这个意图。
感谢:Michael Aufreiter, Adrian Bateman, Oliver Buchtala, Robin Berjon, Enrica Casucci, Bo Cupp, Domenic Denicola, Emil Eklund, Olivier Forget, Aryeh Gregor, Marijn Haverbeke, Yoshifumi Inoue, Koji Ishii, Gary Kacmarcik, Ian Kilpatrick, Frederico Caldeira Knabben, Takayoshi Kochi, Piotrek Koszuliński, Travis Leithead, Grisha Lyukshin, Miles Maxfield, Chaals McCathie Nevile, Masayuki Nakano, Ryosuke Niwa, Julie Parent, Ben Peters, Florian Rivoal, Morgan Smith, Hallvord R. M. Steen, Johan Sörlin, Cristian Talau, Dave Tapuska, Ojan Vafai, Léonie Watson, Xiaoqian Wu, Chong Zhang, Joanmarie 以及编辑任务组中的所有人为他们的意见和反馈。
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: