如何为选中文本添加标签并在其前后闭合/重开父标签?
实现富文本编辑器中选中文字的同级样式拆分
你当前的代码会生成嵌套的span结构,要实现同级拆分的效果,需要把原父元素拆分为三个同级span:保留原样式的前半部分、应用新样式的选中部分、保留原样式的后半部分。具体实现如下:
目标效果对比
原始HTML:
<span class="text-3xl">Foo</span>
期望输出:
<span class="text-3xl">F</span><span class="text-sm">o</span><span class="text-3xl">o</span>
解决方案代码
function splitTextWithStyle(targetClass) { // 检查是否有有效选区 const selection = window.getSelection(); if (selection.rangeCount === 0) return; const range = selection.getRangeAt(0); // 获取选中内容的直接父span(确保操作对象正确) const parentSpan = range.commonAncestorContainer.closest('span'); if (!parentSpan) return; // 拆分内容:选中前、选中内容、选中后 const selectedContent = range.extractContents(); // 提取选中部分之前的内容 const beforeRange = document.createRange(); beforeRange.setStart(parentSpan.firstChild, 0); beforeRange.setEnd(range.startContainer, range.startOffset); const beforeContent = beforeRange.extractContents(); // 提取选中部分之后的内容 const afterRange = document.createRange(); afterRange.setStart(range.endContainer, range.endOffset); afterRange.setEnd(parentSpan.lastChild, parentSpan.lastChild.length); const afterContent = afterRange.extractContents(); // 创建三个同级span const beforeSpan = document.createElement('span'); beforeSpan.className = parentSpan.className; beforeSpan.appendChild(beforeContent); const middleSpan = document.createElement('span'); middleSpan.className = targetClass; middleSpan.appendChild(selectedContent); const afterSpan = document.createElement('span'); afterSpan.className = parentSpan.className; afterSpan.appendChild(afterContent); // 用新的三个span替换原父span const fragment = document.createDocumentFragment(); fragment.append(beforeSpan, middleSpan, afterSpan); parentSpan.parentNode.replaceChild(fragment, parentSpan); // 可选:恢复选区到新样式的文本上 const newRange = document.createRange(); newRange.selectNodeContents(middleSpan); selection.removeAllRanges(); selection.addRange(newRange); }
关键逻辑说明
- 内容拆分:通过
Range对象的extractContents()方法,精准拆分出选中区域的前、中、后三部分内容,避免嵌套结构。 - 元素重建:为前、后部分创建与原父元素同样式的span,中间部分应用目标样式,确保三者同级。
- 替换节点:使用文档片段一次性插入三个span,减少DOM操作次数,提升性能。
- 选区恢复:可选步骤,让用户操作后保持对新样式文本的选中状态,优化交互体验。
内容的提问来源于stack exchange,提问作者Sven Lueck
相关产品推荐
相关产品推荐

