如何让Quill编辑器使用input事件替代keydown事件处理输入?
适配方案
你不需要强制改写Quill的核心事件流,以下两个方案都可以解决移动端event.key为Unidentified导致的转换失效问题,优先选第一个无侵入方案,维护成本最低。
方案一:拦截默认keydown写入,基于beforeinput实现转换(推荐)
- 第一步:阻断Quill在keydown阶段的普通字符默认写入
初始化Quill时覆写keyboard模块的可打印字符处理规则,遇到拿不到有效key值的场景(移动端软键盘输入)直接拦截默认写入逻辑,功能键(退格、回车、方向键等)保留原有行为不影响正常操作:const quill = new Quill('#editor', { theme: 'snow', modules: { keyboard: { bindings: { printable: { key: null, handler: function(range, context, event) { // 能拿到有效key值的场景(PC端物理键盘)走原有逻辑 if (event.key && event.key.length === 1) return true // 拿不到key值(移动端软键盘),阻断默认keydown写入,交给后续输入事件处理 return false } } } } } }) - 第二步:绑定
beforeinput事件做转换逻辑
不要用document级的input事件,直接在Quill的编辑根节点上绑定beforeinput——这个事件触发时机早于内容写入,调用preventDefault()就能100%拦截默认写入,还能直接通过event.data拿到用户实际输入的字符,完全不需要依赖event.key:const editorRoot = quill.root editorRoot.addEventListener('beforeinput', (e) => { // 只处理普通文本插入场景,删除、格式调整、回车等操作走默认逻辑 if (e.inputType !== 'insertText' || !e.data) return // 跳过输入法组合输入阶段,等输入确认后再处理避免截断连写 if (e.isComposing) return e.preventDefault() const selection = quill.getSelection(true) // 对应你原有实现的获取光标前当前匹配词逻辑 const currentWord = this.editorComponent.getCurrentWord(selection.index) const rule = this.converter.convert(e.data, currentWord) // 用Quill原生API写入转换结果,避免破坏内部状态 quill.deleteText(selection.index, selection.length, 'silent') quill.insertText(selection.index, rule.result, 'silent') // 自动把光标移到插入内容末尾 quill.setSelection(selection.index + rule.result.length, 'silent') }) - 兜底兼容:针对少数不支持
beforeinput的旧版安卓浏览器,补一层Quill自带的text-change事件监听,对比增量内容拿到用户输入的字符做转换即可,写入时加source: 'silent'参数避免触发循环更新。
方案二:扩展Quill键盘模块,替换事件绑定逻辑
如果方案一在你当前使用的Quill版本中拦截失效,可以直接扩展内置的Keyboard模块,针对移动端替换事件绑定,不需要改Quill源码:
import Keyboard from 'quill/modules/keyboard' class MobileCompatibleKeyboard extends Keyboard { constructor(quill, options) { super(quill, options) // 移除默认绑定的keydown事件 this.container.removeEventListener('keydown', this.keydownHandler) // 能拿到有效key值的环境保留原有keydown逻辑 if (!/Mobi|Android/i.test(navigator.userAgent)) { this.container.addEventListener('keydown', this.keydownHandler) return } // 移动端绑定beforeinput处理输入 this.container.addEventListener('beforeinput', (e) => { // 在这里实现你的转换逻辑即可,和方案二中的处理逻辑一致 }) } } // 注册自定义模块覆盖默认keyboard模块 Quill.register('modules/keyboard', MobileCompatibleKeyboard, true)
注意:该方案和Quill版本强绑定,后续升级Quill版本时需要重新校验兼容性。
注意事项
- 不要尝试在移动端的
keydown事件里做兼容,软键盘触发keydown时普通字符返回Unidentified是W3C规范的预期行为,没有兼容方案,直接切换到输入事件处理即可。 - 必须处理
compositionstart/compositionend事件,否则用户用系统输入法连写、输入带变音符号的字符时会被转换逻辑截断,输入体验严重受损。 - 所有内容写入、删除操作必须用Quill提供的原生API,不要直接操作DOM,否则会破坏Quill内部的delta状态,导致光标错位、撤销回退功能异常。
内容的提问来源于stack exchange,提问作者s1n7ax
相关产品推荐
相关产品推荐

