自动用
标签将不相关的元素分块包裹起来

前端开发 2026-07-08

我在尝试创建一个脚本,把每一章写作都包裹在一个div元素中,这样就可以在帖子中实现自动排版,而不必每次都手动实现。举一个简单的例子,比如:

<h2>Chapter 1</h2>
<p>bla bla bla bla</p>
<p>bla bla bla bla</p>
<p>bla bla bla bla</p>

<h2>Chapter 2</h2>
<p>bla bla bla bla</p>
<p>bla bla bla bla</p>

<h2>Chapter 3</h2>
<p>bla bla bla bla</p>
<p>bla bla bla bla</p>
<p>bla bla bla bla</p>
<p>bla bla bla bla</p>

<h2>Chapter 4</h2>
<p>bla bla bla bla</p>
<p>bla bla bla bla</p>

然后把它变成:

<div class="chapter" id="chapter-1">
<h2 id="section-1">Chapter 1</h2>
<p>bla bla bla bla</p>
<p>bla bla bla bla</p>
<p>bla bla bla bla</p>
</div>

<div class="chapter" id="chapter-2">
<h2 id="section-2">Chapter 2</h2>
<p>bla bla bla bla</p>
<p>bla bla bla bla</p>
</div>

<div class="chapter" id="chapter-3">
<h2 id="section-3">Chapter 3</h2>
<p>bla bla bla bla</p>
<p>bla bla bla bla</p>
<p>bla bla bla bla</p>
<p>bla bla bla bla</p>
</div>

<div class="chapter" id="chapter-4">
<h2 id="section-4">Chapter 4</h2>
<p>bla bla bla bla</p>
<p>bla bla bla bla</p>
</div>

(这样就能完成排版了,但当我把这部分实现好后,感觉会简单得多。)

我认为类似于 -

h2.insertAdjacentHTML("beforebegin", "</div> + <div class='chapter'>")

...会起作用(我得先创建一个起始的

,这没问题),但显然这不是正确的语法,直接就报错。首先,insertAdjacentHTML似乎只对单一元素有效,其次,像这样插入
标签似的会把它们错误地自动补全,结果类似于 -

<div></div>
<h2>Chapter X</h2>
<p>bla bla bla bla</p>

…这并不是我想要的效果。

我确实在这里发现有人遇到类似的问题 这里,但我的JavaScript知识水平已经低到极点,在没有完整示例供参考的情况下,很难复现给出的答案。

这是我当前正在处理的内容:

// 1. Count total amount of chapters in document
var chapterCount = document.querySelectorAll("h2").length;

// 2. Give all <h2> tags a unique ID, since I can't seem to use insertAdjacentHTML en masse
for (let i = 0; i < chapterCount; i++) {
    document.querySelectorAll("h2")[i].setAttribute("id", "section-" + (i + 1));
}

// 3. This one doesn't work, but you can see the logic I'm going for. Select each <h2> individually, then run the insertAdjacentHTML command on loop until there's no more chapters.
for (let i = 0; i < chapterCount; i++) {
    document.querySelectorAll("#section-") + [i].insertAdjacentHTML("beforebegin", "</div> + <div class='chapter'>");
}

// 4. Assign each chapter a unique ID, so I can set up tabs without issue
for (let i = 0; i < chapterCount; i++) {
    document.querySelectorAll(".chapter")[i].setAttribute("id", "chapter-" + (i + 1));
}

在第3 步,试图按照另外一个问题的思路来做(这个问题也在此链接旁边被提及 这条链接),我尝试了下面类似的解决方案(这并不能解决把它应用到每个

标签的问题,我只是想知道它到底是否起作用):

const targetElement = document.querySelector("h2")
const pseudoContainer = document.createElement('div');
pseudoContainer.innerHTML = "</div><div class='chapter'>";
targetElement.insertAdjacentHTML('beforebegin', pseudoContainer.firstChild);

但最终结果始终只返回 [object HTMLDivElement],而不是我输入的内容。(之所以不是奇怪的、不完整的标签导致的,是因为改成随机文本会返回 [object Text]。)把pseudoContainer.innerHTML插入也不起作用,因为它会像我之前遇到的那样,在标题上方返回一个 。

还有哪些建议可以让我继续?我肯定漏掉了一些非常明显的东西,但我尽量避免使用JavaScript,因为缺乏理解他人讨论中术语的经验。不过这个脚本未来会为我省下大量时间,因此我正在一步一步地学习。

提前感谢!!

解决方案

Selection API的 Range接口提供了一个 surroundContents(newParent) 方法,可以用于此类场景:

const headers = document.querySelectorAll("h2");
for (let i = 0; i<headers.length; i++) {
  const range = new Range();
  range.setStartBefore(headers[i]);
  if (headers[i+1]) {
    range.setEndBefore(headers[i+1]);
  }
  else {
    // use a better selector if needed
    const lastP = document.querySelector("body > p:last-of-type");
    range.setEndAfter(lastP);
  }
  const wrapper = document.createElement("div");
  wrapper.classList.add("wrapper");
  range.surroundContents(wrapper);
}
.wrapper { border: 1px solid; margin: 3px; padding: 6px}
<h2>Chapter 1</h2>
<p>bla bla bla bla</p>
<p>bla bla bla bla</p>
<p>bla bla bla bla</p>

<h2>Chapter 2</h2>
<p>bla bla bla bla</p>
<p>bla bla bla bla</p>

<h2>Chapter 3</h2>
<p>bla bla bla bla</p>
<p>bla bla bla bla</p>
<p>bla bla bla bla</p>
<p>bla bla bla bla</p>

<h2>Chapter 4</h2>
<p>bla bla bla bla</p>
<p>bla bla bla bla</p>
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章