From 8bba2d64af87176ca73b9946e8ccd38374095ede Mon Sep 17 00:00:00 2001 From: Phoenix <64720302+Concur-max@users.noreply.github.com> Date: Tue, 10 Jun 2025 11:03:24 +0800 Subject: [PATCH] =?UTF-8?q?fix(editor):=20=E4=BC=98=E5=8C=96=E6=8F=90?= =?UTF-8?q?=E5=8F=8A=E6=8F=92=E5=85=A5=E9=80=BB=E8=BE=91=E5=B9=B6=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E5=85=89=E6=A0=87=E4=BD=8D=E7=BD=AE=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 重构提及插入逻辑,使用更直接的方式删除@符号到光标间的内容 将普通空格替换为不间断空格以避免被HTML压缩 确保光标始终正确放置在插入内容之后 --- src/components/editor/CustomEditor.vue | 45 +++++++++++++------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/src/components/editor/CustomEditor.vue b/src/components/editor/CustomEditor.vue index d32f597..78d3013 100644 --- a/src/components/editor/CustomEditor.vue +++ b/src/components/editor/CustomEditor.vue @@ -233,39 +233,38 @@ const insertMention = (member, clonedRange) => { const parent = textNode.parentNode; if (!parent) return; // Sanity check - const textBeforeAt = textContent.substring(0, atIndex); - const textAfterCursor = textContent.substring(offset); + // 从@符号开始删除,直到当前光标位置 + range.setStart(textNode, atIndex); + range.setEnd(textNode, offset); + range.deleteContents(); - const beforeNode = document.createTextNode(textBeforeAt); - const spaceAfterMentionNode = document.createTextNode(' '); // Ensure space after mention - const afterNode = document.createTextNode(textAfterCursor); - - parent.insertBefore(beforeNode, textNode); - parent.insertBefore(mentionSpan, textNode); - parent.insertBefore(spaceAfterMentionNode, textNode); - parent.insertBefore(afterNode, textNode); - parent.removeChild(textNode); - - range.setStartAfter(spaceAfterMentionNode); - range.collapse(true); + // 插入 mention 元素 + range.insertNode(mentionSpan); } else { // 如果没有找到@符号,或者光标不在合适的文本节点内,直接在当前光标位置插入 if (!range.collapsed) { range.deleteContents(); } - range.insertNode(mentionSpan); + } - const spaceNode = document.createTextNode(' '); - // 正确地将 range 移动到 mentionSpan 之后再插入空格 - const tempRangeForSpace = range.cloneRange(); // 使用临时 range 避免干扰主 range - tempRangeForSpace.setStartAfter(mentionSpan); - tempRangeForSpace.collapse(true); - tempRangeForSpace.insertNode(spaceNode); - - // 将主 range 移动到新插入的空格之后 + // 在 mention 之后插入一个空格,并将光标移到空格之后 + const spaceNode = document.createTextNode('\u00A0'); // 使用不间断空格 + const currentParent = mentionSpan.parentNode; + if (currentParent) { + // 将空格节点插入到 mentionSpan 之后 + if (mentionSpan.nextSibling) { + currentParent.insertBefore(spaceNode, mentionSpan.nextSibling); + } else { + currentParent.appendChild(spaceNode); + } + // 设置光标到空格之后 range.setStartAfter(spaceNode); range.collapse(true); + } else { + // Fallback: 如果 mentionSpan 没有父节点(理论上不应该发生),则将光标设置在 mentionSpan 之后 + range.setStartAfter(mentionSpan); + range.collapse(true); } selection.removeAllRanges();