contenteditable div聊天输入框插入图片表情后光标位置异常的解决问询
修复Contenteditable输入框插入表情后光标位置异常问题
问题描述
开发简易聊天功能时,采用「父span背景图+子span隐藏真实emoji」的方式实现自定义表情。但将表情插入contenteditable的输入框后,光标会出现在表情元素前方而非预期的后方:比如输入框原有内容hello,插入表情后变为hello(光标)(表情),再次插入则变为hello(光标)(表情)(表情)。
修复方案
问题根源在于原代码仅处理了表情后方存在文本节点的情况,未覆盖表情为最后一个元素的场景。只需修改表情插入后的光标定位逻辑,强制将光标移至表情元素的后方即可。
修改后的完整JS代码
const chatInput = document.querySelector("div#chat-input"); const grinningFace = document.querySelector("span#grinning-face"); const rocket = document.querySelector("span#rocket"); chatInput.addEventListener("keydown", function(event) { if(event.key === "Enter"){ event.preventDefault(); const message = document.createElement("div"); message.textContent = chatInput.innerText; chatInput.innerHTML = ""; } }) grinningFace.addEventListener("mousedown", function(event) { event.preventDefault(); }); grinningFace.addEventListener("click", function() { const content = grinningFace.querySelector("span") const range = document.getSelection().getRangeAt(0); const emojiImage = document.createElement("span"); const emojiImageContent = document.createElement("span"); emojiImage.classList.add("emoji-image"); emojiImage.style.backgroundImage = `${getComputedStyle(grinningFace).backgroundImage}`; emojiImage.style.backgroundSize = "contain"; emojiImageContent.textContent = content.textContent; emojiImage.appendChild(emojiImageContent); range.insertNode(emojiImage); // 修复:强制将光标定位到表情元素后方 const selection = window.getSelection(); const newRange = document.createRange(); newRange.setStartAfter(emojiImage); newRange.collapse(true); selection.removeAllRanges(); selection.addRange(newRange); chatInput.focus(); }); rocket.addEventListener("mousedown", function(event) { event.preventDefault(); chatInput.focus(); });
关键修改说明
原代码仅在表情后方存在文本节点时才调整光标位置,而使用setStartAfter(emojiImage)可以直接将光标锚点设置在表情元素的末尾,无论表情后面是文本节点、元素节点还是没有任何节点,都能确保光标出现在表情后方。
补充:完善火箭表情的插入逻辑
如果需要让火箭表情也具备相同功能,可以复制笑脸表情的点击事件逻辑:
rocket.addEventListener("click", function() { const content = rocket.querySelector("span") const range = document.getSelection().getRangeAt(0); const emojiImage = document.createElement("span"); const emojiImageContent = document.createElement("span"); emojiImage.classList.add("emoji-image"); emojiImage.style.backgroundImage = `${getComputedStyle(rocket).backgroundImage}`; emojiImage.style.backgroundSize = "contain"; emojiImageContent.textContent = content.textContent; emojiImage.appendChild(emojiImageContent); range.insertNode(emojiImage); // 同样设置光标到表情后方 const selection = window.getSelection(); const newRange = document.createRange(); newRange.setStartAfter(emojiImage); newRange.collapse(true); selection.removeAllRanges(); selection.addRange(newRange); chatInput.focus(); });
内容的提问来源于stack exchange,提问作者redd
相关产品推荐
相关产品推荐

