专栏首页KrryblogDOM 元素的循环遍历
原创

DOM 元素的循环遍历

博客地址:https://ainyi.com/89

获取 DOM 元素的几种方式

get 方式:

  1. getElementById
  2. getElementsByTagName
  3. getElementsByClassName
  4. getElementsByName

返回类型 HTMLCollection[]


query 方式:

  1. querySelector
  2. querySelectorAll

返回类型 NodeList[]


获取 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 元素,类似 aindex

==ƒ 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)

博客地址:https://ainyi.com/89

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • for 循环 和 Array 数组对象

    - forEach 不支持 return 和 break,一定会把所有数据遍历完毕

    Krry
  • JavaScript 相关的工具代码

    当前 toLocaleTimeString 方法只能获取到 12 小时制的时间('上午09:10:01' | '下午08:10:24')

    Krry
  • H5 和 CSS3 新特性

    HTML5 拥有多个新的表单 Input 输入类型。这些新特性提供了更好的输入控制和验证

    Krry
  • Neo4j-1.Neo4j基础

    悠扬前奏
  • 路径查找器AI

    问题源于我想建立一个游戏AI,它要能够定义一条从起点到终点的路径,同时避开路上的墙壁障碍物。为此,我写了一个C#库(path.dll),它允许定义一个二维空间(...

    东心木水
  • 关于堆

    Noneplus
  • 【使用教程】手把手教你入门腾讯云服务器

    2)使用购买服务器的微信,扫描二维码登陆,如果非微信账号,可以选择二维码下方其他登录方式

    小西
  • MGR 的主要优点

    MGR(Mysql Group Replication)是5.7版本新加的特性,是一个MySQL插件。

    MySQL轻松学
  • 2018-11-14-window的VirtualScreen

    桌面应用常常会遇到多显示器适配问题,比如我们会期望让小人从最左边的屏幕跑到最右边,或者将一个窗口藏在所有显示器的显示区域之外。

    黄腾霄
  • 家国梦自动收取金币、货物、升级建筑、拆相册等脚本

    1、先PC装按键精灵手机助手 2、把代码复制到按键精灵手机助手上去 3、按键精灵上点“调试”,会自动在模拟器上安装手机版按键精灵 4、按键精灵上点“连接模...

    小锋学长

扫码关注云+社区

领取腾讯云代金券