如何用原生JS给元素部分文本包裹/移除span标签?
原生JS实现指定文本包裹span及反向移除操作
现有元素:
<p id="foo">Hello world!</p>
期望最终状态:
<p id="foo"><span>Hello</span> world!</p>
问题
如何通过纯原生JS实现上述文本包裹span的效果,以及反向移除该span标签的操作?另外想知道surroundContents和createRange是否适用于这个场景?
一、实现文本包裹span的方案
方案1:用createRange + surroundContents(推荐)
这俩完全适配你的场景,代码如下:
const el = document.getElementById('foo'); const textNode = el.firstChild; // 获取p标签内的文本节点 const range = document.createRange(); // 精准选中"Hello"这段文本(从文本节点的第0位到第5位) range.setStart(textNode, 0); range.setEnd(textNode, 5); const newSpan = document.createElement('span'); range.surroundContents(newSpan);
原理:createRange用来定位你要包裹的文本范围,surroundContents直接把选中的内容塞进你创建的span里,一步到位。
方案2:拆分文本节点实现
如果不想用Range API,也可以直接拆分文本节点:
const el = document.getElementById('foo'); const textNode = el.firstChild; // 从第5个字符的位置拆分文本节点,得到后半段" world!"的节点 const remainingText = textNode.splitText(5); // 创建span并把前半段文本移进去 const newSpan = document.createElement('span'); el.insertBefore(newSpan, remainingText); newSpan.appendChild(textNode);
二、反向移除span标签
要移除span但保留里面的文本,直接把span的内容替换掉span本身就行:
const span = document.querySelector('#foo span'); if (span) { // 把span的子节点(这里是文本"Hello")替换掉span span.replaceWith(...span.childNodes); }
或者用更兼容旧浏览器的写法:
const el = document.getElementById('foo'); const span = el.querySelector('span'); if (span) { while (span.firstChild) { el.insertBefore(span.firstChild, span); } el.removeChild(span); }
关于surroundContents和createRange的适用性
createRange是实现这个需求的核心:它能精准定位文档中任意一段连续的内容(包括文本节点的一部分),完全适配局部文本包裹的场景。surroundContents是绝佳的配套工具:它专门用来把Range选中的内容包裹到指定元素中,只要选中的内容是连续且没有跨不完整的元素节点(这里只是文本节点的一部分,完全合法),就能直接生效,非常适合你的需求。
内容的提问来源于stack exchange,提问作者Matt
相关产品推荐
相关产品推荐

