• DOM 元素的循环遍历


    ​原文:https://ainyi.com/31

    获取元素

    首先用两种方式获取元素

    let a = document.getElementsByClassName('title')
    let b = document.querySelectorAll('.title')
    

    一般循环

    get 方式

    get 方式获取的 dom 元素,仅可使用for-in、for-of、for循环

    for(let key in a) {
      console.log(a[key])
    }
    // dom
    // ...(每个dom元素)
    // length(集合长度)
    // ƒ item() { [native code] }
    // ƒ namedItem() { [native code] }
    

    其中:
    ƒ item() { [native code] }
    可通过 a.item(index) 获取 dom 元素,类似 a[index]

    ƒ namedItem() { [native code] }
    可通过 a.namedItem('popo') 获取 name 属性为 'popo' 的 dom 元素(若多个元素有相同的 name 属性,返回第一个)

    for-of、for 循环可获取每个 dom 元素:

    for(let val of a) {
      console.log(val)
    }
    // dom
    // ...(每个dom元素)
    

    for(let i = 0; i < a.length; i++) {
    console.log(a[i])
    }
    // dom
    // ...(每个dom元素)

    query 方式

    query 方式获取的 dom 元素,可使用forEach、for-in、for-of、for循环
    forEach、for-of、for 循环的结果无差别

    但 for-in 相比 get 方式 的 for-in,循环得出的结果稍有不同

    for(let key in b) {
      console.log(b[key])
    }
    // dom
    // ...(每个dom元素)
    // length(集合长度)
    // ƒ item() { [native code] }
    // ƒ entries() { [native code] }
    // ƒ forEach() { [native code] }
    // ƒ keys() { [native code] }
    // ƒ values() { [native code] }
    

    与 get 方式的 for-in 相比,少了 ƒ namedItem() { [native code] },多了 Object 的几个方法
    这说明,query 方式获取的 dom 元素集合,可执行 Object 对应的方法,但没有 namedItem() 方法

    ES6 转换普通数组

    ES6 提供了 Array.from() 方法可将这些集合转换成普通数组,这样就可以享用数组的各种方法了

    let array = Array.from(a)
    

    深度遍历

    节点树的几个属性

    • childElementCount:返回子元素(不包括文本节点和注释)的数量
    • parentNode:ele 的父节点
    • childNodes:ele 的所有的直接子节点
    • nextSibling:ele 的下一个同辈节点
    • previousSibling:ele 的上一个同辈节点

    因为 childNodes 包含看不见的空格文本,还有注释等内容,所以使用起来不是太方便
    因此,js 又重新引入了元素树的概念。这个在我们实际应用中,用的比较普遍

    元素树:仅仅包含元素节点的树结构,不是一颗新树,尽是节点数的子集

    为元素新增了下面几个属性:

    • parentElement:节点的父元素
    • children:返回节点的所有子元素
    • firstElementChild:第一个直接子元素
    • lastElementChild:最后一个直接子元素
    • previousElementSibling:ele 的前一个兄弟元素
    • nextElementSibling:ele 的下个兄弟元素

    一般来说,区别元素节点,属性节点,文本节点的通用方式是判断该节点的 nodeType

    常见的几种 nodeType:

    元素节点:1,
    属性节点:2,
    文本节点:3,
    注释节点:8,
    ...

    遍历直接子级元素

    假设 html 如下,要遍历出 div 中的所有直接子级的元素节点:

    <div id="list">
      <p>hello</p>
      <span>world</span>
      <em>cookieParse()</em>
    </div>
    

    用 firstChild,lastChild 进行元素遍历

    let list = document.getElementById('list')
    

    let child = list.firstChild

    console.log(list.nextSibling)

    while(child != list.lastChild) {
    if(child.nodeType === 1) {
    console.log( child )
    }
    child = child.nextSibling
    }

    使用 firstElementChild,nextElementSibling

    let list = document.getElementById('list')
    

    let child = list.firstElementChild

    while(child) {
    console.log( child )
    child = child.nextElementSibling
    }

    深度优先遍历

    遍历所有节点
    深度优先遍历:当同时有兄弟节点和子节点的时候,总是优先遍历子节点

    function getChildren(parent) {
      // 如果当前节点是元素节点,输出当前元素
      parent.nodeType === 1 && console.log(parent);
      // 获得父节点的所有直接子节点
      let children = parent.childNodes
      // 遍历 children 中每个节点
      for(let i = 0, len = children.length; i<len; i++) {
        // 对当前子节点递归
        getChildren(children[i])
      }
    }
    getChildren(document.body)
    

    需要注意的是:递归的运行效率没有迭代的运行效率高,一般都需要把递归的循环优化成迭代的循环
    所以上面递归算法可以进一步优化

    优化深度优先遍历

    使用 NodeIterator 对象,可以对 DOM 树进行深度优先的搜索

    创建 NodeIterator 对象,需要使用 document 对象的 createNodeIterator 方法,该方法接收四个参数:

    • root:搜索开始的节点
    • whatToShow:一个数值代码,表示哪些节点需要搜索
    • filter:NodeFilter 对象,决定忽略哪些节点
    • entityReferenceExpansion:布尔值,表示是否需要扩展实体引用

    whatToShow 参数:

    参数 意义
    NodeFilter.SHOW_ALL 显示所有类型的节点
    NodeFilter.SHOW_ELEMENT 显示元素节点
    NodeFilter.SHOW_ATTRIBUTE 显示特性节点
    NodeFilter.SHOW_TEXT 显示文本节点
    NodeFilter.SHOW_CDATA_SECTION 显示CDATA节点。对HTML页面无用
    NodeFilter.SHOW_ENTITY_REFERENCE 显示实体引用节点
    NodeFilter.SHOW_ENTITYE 显示实体节点
    NodeFilter.SHOW_PROCESSING_INSTRUCTION 显示处理指令节点
    NodeFilter.SHOW_COMMENT 显示注释节点
    NodeFilter.SHOW_DOCUMENT 显示元档节点
    NodeFilter.SHOW_DOCUMENT_TYPE 显示文档类型节点
    NodeFilter.SHOW_DOCUMENT_FRAGMENT 显示文档片段节点
    NodeFilter.SHOW_SHOW_NOTATION 显示符号节点
    NodeFilter.SHOW_DOCUMENT_TYPE 显示文档类型节点

    优化如下:

    function getChildren(parent){
      // 获取 NodeIterator 对象
      let t = document.createNodeIterator(parent, NodeFilter.SHOW_ELEMENT, null, false)
      // 循环遍历对象的下一个节点
      let currNode = null
      while((currNode = t.nextNode()) !== null) {
        // 节点不为空,就一直循环遍历下去;直到为 null,才中断循环
        console.log(currNode)
      }
    }
    getChildren(document.body)
    
  • 相关阅读:
    爱就是一个人一辈子
    硬件访问方法和混杂字符设备
    Linux内核等待队列
    深入浅出的讲解傅里叶变换(真正的通俗易懂)
    Linux用root强制踢掉已登录用户
    一文带你读懂宽带上下行速率不对称的原因
    FDD-LTE上下行带宽一样的,为什么上下行流量差别这么大
    linux alsa音频中采样率fs、比特率BCLK 、主时钟MCLK关系
    80211 发送速率选择算法分析
    imx6q 启动logo
  • 原文地址:https://www.cnblogs.com/yzmy/p/14710772.html
Copyright © 2020-2023  润新知