You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

页面加载后DOM重构:解决querySelectorAll重复选中元素引发的无限递归问题

Fixing Infinite Recursion & DOM Structure Issues When Wrapping Elements

Let's break down the problems in your code and fix them step by step:

Core Problem: Infinite Recursion

Your querySelectorAll('h1, p') selects all <h1> and <p> elements in the entire subtree of #content—including those already wrapped inside .desc-container divs. This means every recursive call keeps picking up the same wrapped elements, leading to an infinite loop.

Fix 1: Target Only Direct Child Elements

Instead of selecting all descendants, use the :scope pseudo-class to target only direct child elements of #content. This ensures you only process elements that haven't been wrapped yet:

const parentContent = parentBlock.querySelectorAll(':scope > h1, :scope > p')

Fix 2: Correct the Element Matching Logic

Your getIndex function uses a flawed regex (new RegExp('h?')) which matches almost any element (since h? allows zero or one "h" characters). Replace this with a direct check for <h1> elements to properly identify the start of each group:

const getIndex = nodeList => {
  const indexes = { start: -1, end: -1 }
  for (let i = 0; i < nodeList.length; i++) {
    // Look for the first h1 as the group start
    if (nodeList[i].localName === 'h1' && indexes.start < 0) {
      indexes.start = i
    }
    // Stop at the first p after the h1
    if (indexes.start !== -1 && nodeList[i].localName === 'p') {
      indexes.end = i
      break
    }
  }
  return indexes
}

Fix 3: Fix the DOM Structure Assembly

Your original code had a bug in how you appended nodes: mainNode.appendChild(titleNode).appendChild(bodyNode) appends bodyNode inside titleNode, not directly to mainNode. Split this into two separate calls to match your desired structure:

mainNode.appendChild(titleNode)
mainNode.appendChild(bodyNode)

Full Revised Code

Here's the complete working version of your function:

const createComplexNode = () => {
  const parentBlock = document.querySelector('#content')
  // Only select direct child h1/p elements
  const parentContent = parentBlock.querySelectorAll(':scope > h1, :scope > p')
  
  if (parentContent.length === 0) return

  const mainNode = document.createElement('div')
  const titleNode = document.createElement('div')
  const bodyNode = document.createElement('div')
  
  mainNode.className = 'desc-container'
  titleNode.className = 'desc-head'
  bodyNode.className = 'desc-body'

  const indexes = getIndex(parentContent)
  // Exit if no valid group found
  if (indexes.start === -1) return

  // Move the h1 into titleNode (removes it from parentBlock's direct children)
  titleNode.appendChild(parentContent[indexes.start])
  // Move the corresponding p into bodyNode
  if (indexes.end !== -1) {
    bodyNode.appendChild(parentContent[indexes.end])
  }

  // Assemble the container correctly
  mainNode.appendChild(titleNode)
  mainNode.appendChild(bodyNode)
  
  // Add the new container to parentBlock
  parentBlock.appendChild(mainNode)

  // Recurse to process remaining direct child elements
  return createComplexNode()
}

const getIndex = nodeList => {
  const indexes = { start: -1, end: -1 }
  for (let i = 0; i < nodeList.length; i++) {
    if (nodeList[i].localName === 'h1' && indexes.start < 0) {
      indexes.start = i
    }
    if (indexes.start !== -1 && nodeList[i].localName === 'p') {
      indexes.end = i
      break
    }
  }
  return indexes
}

Why This Works

  • :scope > h1, :scope > p ensures we only process elements that are direct children of #content—already wrapped elements are nested inside .desc-container, so they're ignored in subsequent recursive calls.
  • When we use appendChild on elements from parentContent, we're moving them from their original position in #content to the new container. This means each recursive call will only see the next unprocessed <h1> and <p> pair.
  • The corrected node assembly ensures the DOM structure matches exactly what you specified.

内容的提问来源于stack exchange,提问作者Iangyl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 06:48:23