如何遍历整个DOM树

原文链接:[如何遍历整个DOM树(外网原文链接)](https://chrisdeo.github.io/2019/07/20/%E5%A6%82%E4%BD%95%E9%81%8D%E5%8E%86%E6%95%B4%E4%B8%AADOM%E6%A0%91/)

作为前端开发工程师,我们大部分工作内容其实还是围绕着DOM在进行Javascript的编写;为了获取对应的DOM节点,我们通常会使用选择器来直接获取对应的元素。但如果让我们访问一整棵DOM树,针对某个环节进行操作呢?这就需要我们对DOM的基本属性以及树的数据结构有比较深刻的认识了。

nodeType:

在开始遍历操作前,我们先要知道DOM元素nodeType这个属性的意义,它以数字值返回指定节点的节点类型,我们这里只例举常见的几种:
nodeType1时,表明该节点为元素节点,如body、div等;
nodeType2时,表明该节点为属性节点,啥是属性节点呢,其实就是src、target这种,只不过我们平常都是以属性来访问它们而不是将其当属性节点提取出;
nodeType3时,表明该节点为文本节点。


DFS:

在知道以上的基本要素后,我们就可以用深度遍历(DFS)的方式开始递归遍历DOM树:

function traverseByDFS(root){
   if(!root) return;
   if(root.nodeType === 1){
       let len = root.children.length;
       console.log(root.nodeName + " ." + root.className);
       for(let i=0;i<len;i++){
           traverseByDFS(root.children[i]);
       }
   }
}

例如以下这段代码:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div class="root">
        <div class="container">
            <section class="sidebar">
                <ul class="menu"></ul>
            </section>
            <section class="main">
                <article class="post"></article>
                <p class="copyright"></p>
            </section>
        </div>
    </div>
</body>

<script>
    function traverseByDFS(root){
        if(!root) return;
        if(root.nodeType === 1){
            let len = root.children.length;
            console.log(root.nodeName + " ." + root.className);
            for(let i=0;i<len;i++){
                traverseByDFS(root.children[i]);
            }
        }
    }
    traverseByDFS(document.getElementsByClassName('root')[0]);
</script>

</html>

以上代码的运行结果为:
在这里插入图片描述


BFS:

对于DOM树的广度遍历来说,关键是如何保存同层节点的访问顺序以便之后继续对他们的子节点进行遍历,而DOM树本身就是构造完整的,我们直接访问对应节点属性就可以拿到相邻元素、祖先元素以及后代元素的值。所以只需要结合队列的特性就可以保存顺序再通过递归访问即可遍历所有元素。

在这里插入图片描述
BFS代码如下:

function traverseByBFS(root){
    if(!root) return;
    let queue = [];
    let rootFirstKid = root.firstElementChild;
    if (rootFirstKid) {
        queue.unshift(rootFirstKid);
        console.log(queue[0].nodeName + ' .' + queue[0].className);
        while (rootFirstKid.nextElementSibling) {
            queue.unshift(rootFirstKid.nextElementSibling);
            console.log(queue[0].nodeName + ' .' + queue[0].className);
            rootFirstKid = rootFirstKid.nextElementSibling;
        }
        while (queue.length) {
            let whoIsOut = queue.pop(); // 取队列的第一个,其实是在数组的尾部
            traverseByBFS(whoIsOut);
        }
    }
}

例如以下这段代码:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div class="root">
        <div class="container">
            <section class="sidebar">
                <ul class="menu"></ul>
            </section>
            <section class="main">
                <article class="post"></article>
                <p class="copyright"></p>
            </section>
        </div>
    </div>
</body>

<script>
    function traverseByBFS(root){
        if(!root) return;
        let queue = [];
        let rootFirstKid = root.firstElementChild;
        if (rootFirstKid) {
            queue.unshift(rootFirstKid);
            console.log(queue[0].nodeName + ' .' + queue[0].className);
            while (rootFirstKid.nextElementSibling) {
                queue.unshift(rootFirstKid.nextElementSibling);
                console.log(queue[0].nodeName + ' .' + queue[0].className);
                rootFirstKid = rootFirstKid.nextElementSibling;
            }
            while (queue.length) {
                let whoIsOut = queue.pop(); // 取队列的第一个,其实是在数组的尾部
                traverseByBFS(whoIsOut);
            }
        }
    }
    traverseByBFS(document.getElementsByClassName('root')[0]);
</script>

</html>

以上代码的运行结果为:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值