The DOM tree structure
Basic Concepts of DOM Tree Structure
The DOM (Document Object Model) tree is the in-memory representation of an HTML document. When a browser loads an HTML page, it parses the HTML code and constructs a tree-like structure composed of nodes. This tree reflects the hierarchical relationships in the HTML document, where each HTML element, attribute, and text content becomes a node in the tree.
<!DOCTYPE html>
<html>
<head>
<title>Sample Page</title>
</head>
<body>
<h1>Main Heading</h1>
<p>Paragraph Text</p>
</body>
</html>
The DOM tree structure for the simple HTML document above is as follows:
document
├── html
├── head
│ └── title
│ └── "Sample Page"
└── body
├── h1
│ └── "Main Heading"
└── p
└── "Paragraph Text"
Types of DOM Nodes
The DOM tree consists of different types of nodes, each with specific properties and methods:
- Document Node: The root node of the entire document
- Element Node: Nodes corresponding to HTML tags
- Attribute Node: Attributes of HTML elements
- Text Node: Text content within elements
- Comment Node: HTML comments
// Examples of accessing different node types
const docNode = document; // Document node
const elementNode = document.body; // Element node
const attrNode = elementNode.attributes[0]; // Attribute node
const textNode = elementNode.firstChild; // Text node
const commentNode = document.createComment('This is a comment'); // Comment node
DOM Tree Traversal Methods
Traversing the DOM tree is a common task in front-end development. Here are several commonly used traversal methods:
Parent-Child Relationship Traversal
// Get parent node
const parent = element.parentNode;
// Get all child nodes (including text nodes, etc.)
const children = element.childNodes;
// Get first child node
const firstChild = element.firstChild;
// Get last child node
const lastChild = element.lastChild;
Sibling Relationship Traversal
// Get previous sibling node
const prevSibling = element.previousSibling;
// Get next sibling node
const nextSibling = element.nextSibling;
Using querySelector Methods
// Get the first matching element
const firstMatch = document.querySelector('.className');
// Get all matching elements
const allMatches = document.querySelectorAll('div');
DOM Tree Modification Operations
In addition to traversal, we often need to modify the DOM tree structure:
Creating New Nodes
// Create new element
const newDiv = document.createElement('div');
// Create text node
const newText = document.createTextNode('New text content');
// Create attribute node
const newAttr = document.createAttribute('data-custom');
newAttr.value = 'value';
Adding Nodes
// Append child node
parentElement.appendChild(newChild);
// Insert before a specified node
parentElement.insertBefore(newNode, referenceNode);
// Replace child node
parentElement.replaceChild(newChild, oldChild);
Removing Nodes
// Remove child node
parentElement.removeChild(childNode);
// Modern method (no need to know parent node)
element.remove();
DOM Tree Performance Optimization
Frequent DOM operations can impact page performance. Here are some optimization suggestions:
Using Document Fragments
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const div = document.createElement('div');
div.textContent = `Item ${i}`;
fragment.appendChild(div);
}
document.body.appendChild(fragment);
Batch Style Modifications
// Bad practice
element.style.color = 'red';
element.style.backgroundColor = 'blue';
element.style.fontSize = '14px';
// Good practice
element.style.cssText = 'color: red; background-color: blue; font-size: 14px;';
// Better practice
element.className = 'active'; // Use CSS classes
Event Delegation
// Bad practice
document.querySelectorAll('li').forEach(li => {
li.addEventListener('click', handleClick);
});
// Good practice (event delegation)
document.querySelector('ul').addEventListener('click', function(e) {
if (e.target.tagName === 'LI') {
handleClick(e);
}
});
Concept of Virtual DOM
Modern front-end frameworks like React and Vue use Virtual DOM technology to improve performance:
// Simplified Virtual DOM example
const virtualDom = {
type: 'div',
props: {
className: 'container',
children: [
{
type: 'h1',
props: {
children: 'Hello World'
}
},
{
type: 'p',
props: {
children: 'This is a paragraph'
}
}
]
}
};
// Render Virtual DOM to real DOM
function render(vnode) {
if (typeof vnode === 'string') {
return document.createTextNode(vnode);
}
const node = document.createElement(vnode.type);
if (vnode.props) {
Object.keys(vnode.props).forEach(prop => {
if (prop !== 'children') {
node.setAttribute(prop, vnode.props[prop]);
}
});
if (vnode.props.children) {
vnode.props.children.forEach(child => {
node.appendChild(render(child));
});
}
}
return node;
}
document.body.appendChild(render(virtualDom));
DOM Tree Access Control
For security reasons, browsers impose some restrictions on DOM access:
Same-Origin Policy
// Cross-domain iframe access will be blocked
try {
const iframe = document.getElementById('foreign-iframe');
const iframeDoc = iframe.contentDocument; // Security error
} catch (e) {
console.error('Same-origin policy blocked access:', e);
}
Shadow DOM
Web components use Shadow DOM to encapsulate internal structures:
class MyComponent extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({mode: 'open'});
shadow.innerHTML = `
<style>
p { color: red; }
</style>
<p>Shadow DOM content</p>
`;
}
}
customElements.define('my-component', MyComponent);
DOM Tree Debugging Techniques
Browser developer tools provide powerful DOM debugging features:
- Element Inspection: Right-click on a page element and select "Inspect"
- DOM Breakpoints: Set subtree modification breakpoints on elements
- Console Access:
$0
references the currently selected element - Monitoring Property Changes:
Object.getOwnPropertyDescriptor(element, 'property')
// Debugging DOM in the console
const el = document.querySelector('div');
// Monitoring property changes
Object.defineProperty(el, 'hidden', {
set: function(value) {
debugger; // Trigger debugger
this.setAttribute('hidden', value);
}
});
DOM Tree Compatibility Issues
Different browsers implement DOM differently, so be aware of:
Event Handling Differences
// Standardized event handling
function addEvent(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent('on' + type, handler);
} else {
element['on' + type] = handler;
}
}
Style Retrieval Differences
// Get computed styles
function getStyle(element, property) {
if (window.getComputedStyle) {
return window.getComputedStyle(element)[property];
} else {
return element.currentStyle[property]; // IE
}
}
Modern DOM APIs
Browsers continue to add new DOM APIs to simplify operations:
MutationObserver
// Monitor DOM changes
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
console.log('DOM changed:', mutation.type);
});
});
observer.observe(document.body, {
childList: true,
attributes: true,
subtree: true
});
IntersectionObserver
// Monitor element visibility
const io = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log('Element entered viewport:', entry.target);
}
});
});
document.querySelectorAll('.lazy-load').forEach(el => {
io.observe(el);
});
Extended Applications of DOM Trees
The concept of DOM trees can be extended to other domains:
XML Document Processing
const xmlString = `<books>
<book>
<title>Professional JavaScript</title>
<author>Nicholas C. Zakas</author>
</book>
</books>`;
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlString, "text/xml");
const titles = xmlDoc.getElementsByTagName('title');
console.log(titles[0].textContent); // "Professional JavaScript"
SVG Manipulation
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute("width", "100");
svg.setAttribute("height", "100");
const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
circle.setAttribute("cx", "50");
circle.setAttribute("cy", "50");
circle.setAttribute("r", "40");
circle.setAttribute("fill", "red");
svg.appendChild(circle);
document.body.appendChild(svg);
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn