jQuery中role=textbox的div替换Emoji后光标复位问题求助
解决contenteditable div替换Emoji后光标跳转到开头的问题
场景:开发一款即时通讯网页的Electron移植版本,网页原生不支持Emoji功能,因此实现了一套文本解析系统,将配置的Emoji字符串替换为对应Emoji。但遇到问题:每次替换Emoji后,光标会回到div的开头。目标div是设置了role=textbox的contenteditable元素,不希望修改其核心HTML,仅通过后台脚本解决。
原相关代码
JavaScript代码
$(window).on('keyup', function(e) { // 如果按下的不是回车键,则继续执行 if (!(e.key === 'Enter')) { // 获取当前聚焦的元素 let focus = $(":focus"); // 校验元素类名,确认是目标文本框 if (focus.attr('class') == "euyIb") { // 获取文本框的文本内容 let text = focus.text(); // 统计字符串中特殊字符":"的数量 let count = (text.split(":").length - 1); // 如果特殊字符数量不少于2,则假设存在可替换的Emoji if (count >= 2) { // 创建字符串中包含的Emoji数组 let contains = []; // 遍历所有配置的Emoji,检查是否存在于字符串中 for (emoji in replaceables) { let target = replaceables[emoji]; if (text.includes(`:${target.name}:`)) { contains.push({ name: `:${target.name}:`, emoji: target.emoji }); } } for (inst in contains) { let item = contains[inst]; $(":focus").text(text.replace(item.name, item.emoji)); // 此处应将光标重置到末尾 } } } } });
HTML结构
<div role="textbox" dir="auto" class="euyIb" contenteditable="true" placeholder="Send a chat" style="caret-color: rgb(242, 60, 87);" id="enter-box">hi 💀</div>
解决方案
核心思路是:替换文本后,通过原生DOM API手动将光标定位到内容末尾,无需修改目标div的核心HTML,仅在现有脚本中添加光标定位逻辑。
步骤1:添加光标定位函数
定义一个用于将光标移动到contenteditable元素末尾的函数:
function moveCursorToEnd(element) { const range = document.createRange(); const selection = window.getSelection(); range.selectNodeContents(element); range.collapse(false); // 折叠到内容末尾 selection.removeAllRanges(); selection.addRange(range); }
步骤2:修改原脚本,替换文本后调用光标定位
调整原替换逻辑,先在内存中完成所有文本替换,再一次性更新DOM并定位光标:
$(window).on('keyup', function(e) { if (!(e.key === 'Enter')) { let focus = $(":focus"); if (focus.attr('class') === "euyIb") { let text = focus.text(); let count = (text.split(":").length - 1); if (count >= 2) { let contains = []; for (emoji in replaceables) { let target = replaceables[emoji]; if (text.includes(`:${target.name}:`)) { contains.push({ name: `:${target.name}:`, emoji: target.emoji }); } } // 先在内存中完成所有替换,减少DOM操作次数 let updatedText = text; contains.forEach(item => { updatedText = updatedText.replace(item.name, item.emoji); }); focus.text(updatedText); // 将光标移到内容末尾 moveCursorToEnd(focus[0]); } } } });
关键优化点
- 原代码循环调用
text()替换会触发多次DOM重绘,现在改为内存中批量替换后一次性更新,提升性能。 - 使用原生DOM API操作光标,确保对contenteditable元素的兼容性,无需依赖jQuery的额外方法。
内容的提问来源于stack exchange,提问作者SpecifiesDev
相关产品推荐
相关产品推荐

