如何遍历整个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>

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/495626.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AMD本月发布的成本优化型Spartan UltraScale+ FPGA系列

随着 FPGA 在更多应用中的使用&#xff0c;AMD 推出了最新的成本、功耗与性能平衡的系列产品。为了扩展其可编程逻辑产品组合&#xff0c;AMD最近推出了最新的成本优化型 Spartan FPGA 系列。随着 FPGA 应用于越来越多的产品和设备&#xff0c;设计人员可能经常发现自己正在寻找…

前端实现浏览器自定义滚动条

前言&#xff1a; 最近有个项目&#xff0c;产品觉得浏览器默认滚动条太丑了。想美化一下&#xff0c;比如自定义颜色&#xff0c;加上圆角&#xff0c;宽高都要更改一下。我查了资料和文档总结了一下 写法&#xff0c;特此记录以便之后使用。 浏览器滚动条api 总结&#xff…

git基础-tagging

tagging 与大多数版本控制系统一样&#xff0c;Git具有将存储库历史中的特定点标记为重要tag的能力。通常&#xff0c;人们使用此功能来标记发布点&#xff08;例如v1.0&#xff0c;v2.0等&#xff09;。在本节中&#xff0c;将学习如何列出现有的标签&#xff0c;如何创建和删…

智慧公厕的技术融合策略

智慧公厕是迎合现代城市发展需要的一项重要基础设施&#xff0c;其设计的技术融合策略在实现公共厕所泛在感知、互通互联、协同构筑智慧城市等方面起到了关键作用。本文将以智慧公厕源头实力厂家广州中期科技有限公司&#xff0c;大量精品案例现场实景实图实例&#xff0c;从物…

【MybatisPlus-updateById】| 更新字段失效 | 很难受的一个BUG

目录 一. &#x1f981; 写在前面二. &#x1f981; 探索过程三. &#x1f981; 原理解释四. &#x1f981; 最后 一. &#x1f981; 写在前面 如题所言&#xff0c;很难受&#xff01;&#xff01;&#xff01; 原因是 &#x1f981; 在写项目的时候&#xff0c;使用 Mybatis…

Docker大全

Docker大全 Docker安装准备工作开启虚拟机系统卸载Docker在线安装Docker离线安装Docker Docker服务基本操作启动docker服务查看docker状态设置docker开机自启禁用docker开机自启重新启动docker服务查看docker信息查看docker info中具体key的信息停止docker服务docker镜像加速 D…

高效沟通:总裁口才提升之道

高效沟通&#xff1a;总裁口才提升之道 在当今这个信息爆炸的时代&#xff0c;沟通已经成为了企业与个人之间不可或缺的一部分。而对于企业的总裁来说&#xff0c;良好的口才更是其领导力的体现和成功的保障。因此&#xff0c;如何提升总裁的口才&#xff0c;实现高效沟通&…

2024运维堡垒机品牌排名看这里!

2024运维堡垒机品牌排名看这里&#xff01; 1、行云管家 2、天磊卫士 3、阿里云 4、华为云 5、安恒 6、JumpServer 7、山石网科 8、齐治 9、启明星辰 10、奇安信 11、迪普科技 12、腾讯云 13、中远麒麟 备注&#xff1a;以上排名不分先后 运维堡垒机定义 运维堡…

Chrome 插件打包发布

插件打包发布 一、打包成 zip 包 最简单方便的一种其实就是打包成 zip 包&#xff0c;通过下载链接进行下载&#xff0c;在包里面通过设置版本号和数据库的版本号对比来提醒用户进行新包的下载。 二、发布到 Chrome 应用商店 1. 注册成为开发者 在发布到 chrome 应用商店之…

Linux系统使用Docker部署MongoDB数据库并实现无公网IP远程访问

文章目录 前言1. 安装Docker2. 使用Docker拉取MongoDB镜像3. 创建并启动MongoDB容器4. 本地连接测试5. 公网远程访问本地MongoDB容器5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定TCP地址远程访问 前言 本文主要介绍如何在Linux Ubuntu系统使用Docker快速部署Mon…

【Java程序设计】【C00387】基于(JavaWeb)Springboot的校园食堂订餐系统(有论文)

基于&#xff08;JavaWeb&#xff09;Springboot的校园食堂订餐系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;已经做了六年的毕业设计程序开发&#xff0c;开发过…

企业如何申请邓白氏编码(DUNS)呢?

尤其是食品企业&#xff0c;药品企业在申请美国FDA认证的时候&#xff0c;经常会听到一个名词——“邓白氏编码”&#xff0c;申请邓白氏编码是企业顺利完成FDA注册认证的必要前提&#xff0c;因此都需要提供邓白氏编码。 今天&#xff0c;小编就来为大家详细介绍下邓白氏编码…

前端大文件分片上传

1.分片上传整体流程 开始上传&#xff1a;前端启动文件分片上传。后端返回唯一标识。分片上传&#xff1a;获取到上传的文件&#xff0c;然后设置一个固定的分片大小&#xff0c;将文件切成多个小片&#xff0c;计算出每一个分片的MD5值&#xff08;32位&#xff09;。将每个分…

证书(公钥):网络安全的关键

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【算法刷题】链表笔试题解析(1)

一、链表分割 题目描述&#xff1a; 链接&#xff1a;链表分割 题目分析&#xff1a; 这题直接处理并不好做&#xff0c;我们可以构建前后两个链表&#xff0c;将小于x值的结点放在链表a内&#xff0c;将其它结点放在链表b内&#xff0c;这样将原链表遍历完后&#xff0c;原链…

OSCP靶场--image

OSCP靶场–image 考点(CVE-2023-34152 suid strace提权) 1.nmap扫描 ## ┌──(root㉿kali)-[~/Desktop] └─# nmap -Pn -sC -sV 192.168.178.178 --min-rate 2500 Starting Nmap 7.92 ( https://nmap.org ) at 2024-03-27 23:43 EDT Nmap scan report for 192.168.178.17…

手机照片恢复:两种方法轻松找回您的珍贵照片!

我们的日常生活中&#xff0c;苹果手机已经成为了记录珍贵时刻的得力工具&#xff0c;而其中最重要的要数照片了。然而&#xff0c;有时候不可避免地会出现误删照片的情况&#xff0c;可能是因为手误、设备故障或其他原因。 当您发现重要的照片不见了&#xff0c;往往会感到焦…

「18」如何让你直播间增加高级质感,效果滤镜是你不二选择?

「18」效果滤镜给你的布景增加质感&#xff0c;更具视觉效果 首先&#xff0c;安装&#xff08;模糊滤镜的‘streamfx’&#xff09;安装包。安装成功后&#xff0c;StreamFX 会出现在 OBS 的菜单栏上。在OBS软件里滤镜可分为效果滤镜和音视频滤镜。 一、音视频滤镜 在选择「…

yolov8 pose keypoint解读

yolov8进行关键点检测的代码如下&#xff1a; from ultralytics import YOLO# Load a model model YOLO(yolov8n.pt) # pretrained YOLOv8n model# Run batched inference on a list of images results model([im1.jpg, im2.jpg]) # return a list of Results objects# Pr…

阿里云效CICD流水线提交前后端项目

后端 一、新建流水线 1进入流水线 2新建流水线 3选择流水线模板 二、上传后端项目 1 将后端项目发布至代码仓库后&#xff0c;在流水线中选择流水线源 我们在选择流水线源之后会出现扫描失败的情况 查看日志发现是因为我们的项目是多模块项目&#xff0c;再扫描的时候无法在…