如何跨所有站点通用判断用户输入是否位于富文本编辑器中
通用判断方案
所有网页端的可编辑场景都遵循W3C标准规范,不需要针对特定富文本编辑器做定制适配,用原生API即可实现全场景覆盖的通用判断。
你原有逻辑存在两个核心缺陷:
- 判断方向错误:选中文本位于输入框/编辑器内部时,应该从选中节点向上遍历祖先节点判断是否属于可编辑区域,而不是向下查找子元素中是否存在input标签
- 覆盖场景不全:完全漏掉了
<textarea>标签、以及所有带contenteditable="true"属性的元素——目前所有网页富文本编辑器(包括文档类产品、各类第三方编辑器)全部基于这个原生属性实现,没有例外。
通用判定规则
只要命中以下任意一条规则,就说明用户当前处于文本编辑场景,需要拦截翻译触发:
- 当前焦点元素是可输入类型的
<input>(排除button、checkbox、radio、hidden、submit等不可输入文本的input类型) - 当前焦点元素是
<textarea> - 当前焦点元素的
isContentEditable属性为true - 从选中文本的锚点节点向上遍历DOM树,任意祖先节点满足上述三个条件
- 兜底判断当前文档
designMode属性为on,兼容部分老旧富文本编辑器的整页编辑模式
注意:不要手动遍历判断元素的
contenteditable属性值,这个属性支持继承,手动判断会漏掉“祖先节点开启可编辑、自身未设置属性”的场景,直接使用浏览器原生提供的isContentEditable属性即可,浏览器会自动处理继承逻辑,兼容性覆盖所有主流浏览器。
修正后的实现代码
替换原有按键触发逻辑即可,无需依赖第三方库:
// 通用方法:判断当前选区是否处于可编辑区域 function isSelectionInEditableArea(selection) { // 优先判断当前激活的焦点元素,处理input/textarea这类替换元素选区不暴露在DOM树的问题 const activeEl = document.activeElement; if (activeEl) { const tagName = activeEl.tagName?.toLowerCase(); if (tagName === 'input') { const inputType = activeEl.type?.toLowerCase(); const nonEditableInputTypes = ['button', 'checkbox', 'radio', 'hidden', 'submit', 'reset', 'image', 'file']; if (!nonEditableInputTypes.includes(inputType)) return true; } if (tagName === 'textarea') return true; if (activeEl.isContentEditable) return true; } if (!selection.rangeCount) return false; const anchorNode = selection.anchorNode; let currentNode = anchorNode.nodeType === Node.TEXT_NODE ? anchorNode.parentElement : anchorNode; // 从选中节点向上遍历DOM树检查 while (currentNode && currentNode !== document.body) { const tagName = currentNode.tagName?.toLowerCase(); if (tagName === 'input') { const inputType = currentNode.type?.toLowerCase(); const nonEditableInputTypes = ['button', 'checkbox', 'radio', 'hidden', 'submit', 'reset', 'image', 'file']; if (!nonEditableInputTypes.includes(inputType)) return true; } if (tagName === 'textarea') return true; if (currentNode.isContentEditable) return true; currentNode = currentNode.parentElement; } // 兜底整页编辑模式 return document.designMode === 'on'; } // 修改后的按键触发逻辑 if (keyCode == "T") { const userSelection = window.getSelection(); if (!isSelectionInEditableArea(userSelection)) { const selectedText = userSelection.toString().trim(); if (selectedText.length > 0) { getTranslate(selectedText); } } }
适配说明
这个方案兼容所有网页场景:普通输入框、文本域、所有基于标准API实现的富文本编辑器、在线文档类产品,不需要做站点级或者编辑器级的特殊适配。
内容的提问来源于stack exchange,提问作者张相楠
相关产品推荐
相关产品推荐

