Traversing the DOM
Purpose
Traversing the DOM to access each node and element.
Result
Depth First Search(DFS)
<div> <p> "hello" <br> "world" <img> comment <ul> <li> "A" <li> "B"
Breadth-First Search(BFS)
<div> <p> <img> comment <ul> "hello" <br> <li> <li> "world" "A" "B"
Access Node
/**
* Access node
* @param n node
*/
function accessNode(n: Node) {
if (n instanceof Comment) {
// comment
console.info('Comment node -', n.textContent)
}
if (n instanceof Text) {
// text
const t = n.textContent?.trim()
if (t) {
console.info('Text node -', t)
}
}
if (n instanceof HTMLElement) {
// element
console.info('Element node ---', `<${n.tagName.toLowerCase()}>`)
}
}
DFS
Recursion
Pay attention to stack overflow problems.
/**
* DFS
* @param root dom node
*/
function dfsTraverse(root: Node) {
visitNode(root)
const childNodes = root.childNodes // .childNodes and .children not the same
if (childNodes.length) {
childNodes.forEach(child => {
dfsTraverse(child) // recursion
})
}
}
Stack
/**
* DFS
* @param root dom node
*/
function depthFirstTraverse2(root: Node) {
const stack: Node[] = []
// push root into stack
stack.push(root)
while (stack.length > 0) {
const curNode = stack.pop() // move out from stack
if (curNode == null) break
visitNode(curNode)
//// child node move into stack
const childNodes = curNode.childNodes
if (childNodes.length > 0) {
// reverse order move into stack
Array.from(childNodes).reverse().forEach(child => stack.push(child))
}
}
}
BFS
Queue
/**
* BFS
* @param root dom node
*/
function breadthFirstTraverse(root: Node) {
const queue: Node[] = [] // Array vs link list
// root node into queue
queue.unshift(root)
while (queue.length > 0) {
const curNode = queue.pop()
if (curNode == null) break
visitNode(curNode)
// child array into array
const childNodes = curNode.childNodes
if (childNodes.length) {
childNodes.forEach(child => queue.unshift(child))
}
}
}