DOM中BFS(广度优先遍历)和DFS(深度优先遍历)的方法

广度优先遍历,即父层遍历结束,才开始遍历子层,然后一直往下遍历,如果是下面这样一颗DOM树

<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>

则需要遍历为

DIV .root
DIV .container
SECTION .sidebar
SECTION .main
UL .menu
ARTICLE .post
P .copyright

这种形式,平级的子元素显示在一起,并且最好隔开,这样更容易理解。下面就开始写BFS的实现方法。

首先需要一个打印函数,便于打印信息

let printInfo = (node) => {
    console.log(node.tagName, '.' + node.className)

然后是遍历函数,遍历中需要一个中间数组,即父层遍历时每遍历一个元素即将此元素的子元素写入中间数组,遍历完之后,如果此数组长度不为0,则接着遍历下一层,直至最后一层。

// root为你需要遍历的根节点,此处为.root
let root = document.getElementsByClassName('root')[0]

// 此时遍历的为current,记录下一层遍历的为nextRound,初始值为root
let current = []
let nextRound = [root]

// 遍历函数
function bfs () {
    current = nextRound
    // 将nextRound重置,切记不可直接设置length为0,这样current也会重置
    nextRound = []
    Array.from(current).forEach(function (el) {
        printInfo(el)
        Array.from(el.children).forEach(function (element) {
            nextRound.push(element)
        })
    })
}

// 开始遍历
while(nextRound.length){
    bfs()
}

深度优先遍历以深度为主,即遍历完某一个节点之后,才会继续往下遍历兄弟节点,这个只需要循环遍历就行了。

function dfs (node) {
    printInfo(node)
    if(node.children.length){
        Array.from(node.children).forEach(function (el) {
            dfs(el)
        })
    }
}

dfs(root)

这样打印出来的就是

DIV .root
DIV .container
SECTION .sidebar
UL .menu
SECTION .main
ARTICLE .post
P .copyright

还有一点就是childNodes和children这两个时不太一样的,childNodes会将文本节点也打印出来,这时候你就会看到很多undefined .undefined这样的东西,所以尽量使用children,然后用Array.from将其从HTMLCollection变为一个真正的数组。

本文参考: https://juejin.im/post/58f558efac502e006c3e5c97,王仕军的掘金专栏

点赞