为了账号安全,请及时绑定邮箱和手机立即绑定

不排除元素的 DOM 遍历

不排除元素的 DOM 遍历

三国纷争 2023-10-24 21:49:46
我正在创建一个简单的脚本,它遍历 DOM 并返回一个树对象,其中包含在 DOM 中找到的元素。递归遍历本身非常简单,但我想要/需要跳过某些元素并包含其他元素。我该怎么做呢?这是我的 HTML:<div data-element="from-here">  <div>skip me</div>  <div>    <div data-element="awesome">awesome text</div>    <div data-element="collect-me">      awesome text      <div data-element="also-me">        other text        <div class="but-not-me">...</div>      </div>    </div>  </div></div>还有我的递归遍历代码:const root = document.querySelector('[data-element="from-here"]');function traverse(node) {  return {    element: node.dataset.element,    children: Array.from(node.querySelectorAll(':scope > div')).map(childNode => traverse(childNode)),  };}traverse(root);正如您所看到的,代码查询所有 div 元素,但我只需要带有data-element属性的元素。我不能只执行 `node.querySelectorAll(':scope > [data-element]') 因为这不会超出第一个 div。这就是我想要的结果:{  element: 'from-here',  children: [    {      element: 'awesome',      children: [],    },    {      element: 'collect-me',      children: [        {          element: 'also-me',          children: [],        }      ]    }  ]}任何帮助将不胜感激!
查看完整描述

3 回答

?
郎朗坤

TA贡献1921条经验 获得超9个赞

使用Array.prototype.flatMap可以大大降低转换的复杂性 -

  1. 如果节点没有值data-element

  2. 不包含节点;仅包括其子项的结果。

  3. 否则(通过归纳)该节点确实具有data-element值。将其包含element在输出中以及该节点的children.

上面的编号点对应于下面的源评论 -

const root = document.querySelector('[data-element="from-here"]');


const toTree = ({ dataset = {}, children = [] }) =>

  dataset.element === undefined              // 1

    ? Array.from(children).flatMap(toTree)   // 2

    : [ { element: dataset.element           // 3

        , children: Array.from(children).flatMap(toTree)

        }

      ]


console.log(toTree(root)[0])

<div data-element="from-here">

  <div>skip me</div>

  <div>

    <div data-element="awesome">awesome text</div>

    <div data-element="collect-me">

      awesome text

      <div data-element="also-me">

        other text

        <div class="but-not-me">...</div>

      </div>

    </div>

  </div>

</div>

请注意,上面我们没有使用querySelectorAll,因为不需要额外的文档查询。然而,一些明显的改进是 -

  1. 将树的形状定义为单独的函数,branch

  2. 为重复任务定义一个助手,allToTree

const branch = (element = "", children = []) =>    // 1

  ({ element, children })


const allToTree = (nodes = []) =>                  // 2

  Array.from(nodes).flatMap(toTree)

toTree现在已经摆脱了复杂性。我们的意图很明确,每个功能都易于编写、测试和维护 -


const toTree = ({ dataset = {}, children = [] }) =>

  dataset.element === undefined

    ? allToTree(children)

    : [ branch(dataset.element, allToTree(children) ]


查看完整回答
反对 回复 2023-10-24
?
鸿蒙传说

TA贡献1865条经验 获得超7个赞

您可以使用Array.filter()它来过滤掉没有属性的元素data-element。


但为了包含包装器 div,您可能data-element还需要添加属性,如下所示。


const root = document.querySelector('[data-element="from-here"]');


function traverse(node) {

  if (node.dataset.element) {

    return {

      element: node.dataset.element,

      children: Array.from(node.querySelectorAll(':scope > div'))

        .filter(child => {

          return child.dataset.element || Array.from(child.children).some(grandChild => grandChild.dataset.element)

         // If element has dataset     or  The child has some children with dataset attribute

        })

        .map(childNode => traverse(childNode)),

    };

  } else if (Array.from(node.children).some(child => child.dataset.element)) {

    return Array.from(node.querySelectorAll(':scope > div')).filter(child => child.dataset.element).map(childNode => traverse(childNode))

  }

}


console.log(traverse(root));

<div data-element="from-here">

  <div>skip me</div>

  <div>

    <div data-element="awesome">awesome text</div>

    <div data-element="collect-me">

      awesome text

      <div data-element="also-me">

        other text

        <div class="but-not-me">...</div>

      </div>

    </div>

  </div>

</div>


查看完整回答
反对 回复 2023-10-24
?
呼啦一阵风

TA贡献1802条经验 获得超6个赞

为什么不使用 usingnode.querySelectorAll(':scope [data-element]')来代替呢?这将覆盖具有该属性的所有元素,而不仅仅是第一层子元素。

这是一个小提琴: https: //jsfiddle.net/cp21ykng/2/或者我错过了什么?


查看完整回答
反对 回复 2023-10-24
  • 3 回答
  • 0 关注
  • 116 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信