如何通过Chrome扩展内容脚本替换DraftJS编辑器选中文本为等长问号
实现方案:通过Web API替换DraftJS编辑器选中文本为等长问号
核心思路
DraftJS编辑器虽基于React,但最终会渲染成带contenteditable="true"的DOM容器。我们可以直接操作DOM的Selection和Range对象,模拟用户输入触发编辑器内容更新,无需直接操作React状态。
具体实现步骤
1. 定位DraftJS编辑器的可编辑容器
DraftJS的编辑器通常会生成一个contenteditable="true"的元素,可通过以下方式定位:
- 精准选择器:
div[contenteditable="true"].DraftEditor-editorContainer - 通用选择器:
document.querySelector('[contenteditable="true"]')(适用于页面仅有一个可编辑区域的场景)
2. 编写替换选中文本的核心函数
利用window.getSelection()获取当前选中范围,替换为等长问号:
function replaceSelectedTextWithQuestionMarks() { const selection = window.getSelection(); // 校验是否有有效选中内容 if (!selection.rangeCount || selection.isCollapsed) return; const range = selection.getRangeAt(0); const selectedText = range.toString(); const questionMarks = '?'.repeat(selectedText.length); // 删除选中内容并插入问号文本 range.deleteContents(); const textNode = document.createTextNode(questionMarks); range.insertNode(textNode); // 将光标定位到替换文本末尾 range.setStartAfter(textNode); range.setEndAfter(textNode); selection.removeAllRanges(); selection.addRange(range); // 触发input事件,让DraftJS同步内容到内部状态 const editorContainer = range.commonAncestorContainer.closest('[contenteditable="true"]'); if (editorContainer) { const inputEvent = new Event('input', { bubbles: true, cancelable: true }); editorContainer.dispatchEvent(inputEvent); } }
3. 注入按钮并绑定点击事件
在内容脚本中生成按钮,添加到页面并绑定替换函数:
// 生成并注入按钮 function injectButton() { const button = document.createElement('button'); button.textContent = '替换为问号'; button.style.position = 'fixed'; button.style.top = '20px'; button.style.right = '20px'; button.style.zIndex = '9999'; button.style.padding = '8px 16px'; button.style.cursor = 'pointer'; button.addEventListener('click', replaceSelectedTextWithQuestionMarks); document.body.appendChild(button); } // 页面加载完成后执行注入 if (document.readyState === 'complete') { injectButton(); } else { window.addEventListener('load', injectButton); }
关键说明
- 触发input事件的必要性:DraftJS通过监听DOM的input事件同步React状态,手动修改DOM后触发该事件,能让编辑器识别内容变化并更新内部状态。
- 兼容性:
window.getSelection()和Range对象在Chrome等现代浏览器中支持良好,无需额外兼容处理。 - 范围校验:通过
range.commonAncestorContainer.closest('[contenteditable="true"]')确保仅操作DraftJS编辑器内的选中内容,避免修改页面其他区域文本。
内容的提问来源于stack exchange,提问作者Osama Akhtar
相关产品推荐
相关产品推荐

