DOM树与节点操作
DOM树将HTML文档解析为节点树结构,JavaScript可动态操作节点。
DOM树结构
节点层级
JavaScript
Document(文档节点)
├── Element(元素节点)
│ ├── Element
│ │ └── Text(文本节点)
│ └── Element
│ ├── Comment(注释节点)
│ └── Text
└── DocumentType(文档类型)
节点类型
JavaScript
const el = document.querySelector('.box');
// 节点类型
el.nodeType; // 1 (Element)
el.nodeName; // 'DIV'
el.nodeValue; // null(元素节点)
// 文本节点
const text = el.firstChild;
text.nodeType; // 3 (Text)
text.nodeValue; // 文本内容
| nodeType | 类型 | 说明 |
|---|---|---|
| 1 | Element | 元素节点 |
| 3 | Text | 文本节点 |
| 8 | Comment | 注释节点 |
| 9 | Document | 文档节点 |
| 10 | DocumentType | 文档类型 |
| 11 | DocumentFragment | 文档片段 |
创建节点
createElement
JavaScript
// 创建元素
const div = document.createElement('div');
const p = document.createElement('p');
const span = document.createElement('span');
// 设置属性
div.id = 'container';
div.className = 'wrapper';
div.setAttribute('data-id', '123');
createTextNode
JavaScript
// 创建文本节点
const text = document.createTextNode('Hello World');
createComment
JavaScript
// 创建注释节点
const comment = document.createComment('这是一个注释');
DocumentFragment
JavaScript
// 创建文档片段(批量操作优化)
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const li = document.createElement('li');
li.textContent = `项目${i}`;
fragment.appendChild(li);
}
// 一次性插入
list.appendChild(fragment);
插入节点
appendChild
JavaScript
const parent = document.querySelector('.container');
const child = document.createElement('div');
// 添加到末尾
parent.appendChild(child);
// 返回插入的节点
const inserted = parent.appendChild(child);
insertBefore
JavaScript
const parent = document.querySelector('.container');
const newChild = document.createElement('div');
const refChild = parent.querySelector('.reference');
// 在refChild之前插入
parent.insertBefore(newChild, refChild);
// 插入到第一个子元素之前
parent.insertBefore(newChild, parent.firstElementChild);
// 插入到末尾(ref为null)
parent.insertBefore(newChild, null);
append/prepend
JavaScript
const parent = document.querySelector('.container');
// 末尾添加多个
parent.append(div, span, '文本');
// 开头添加多个
parent.prepend(div, span);
// 注意:append/prepend可以添加字符串(自动转为文本节点)
after/before
JavaScript
const el = document.querySelector('.item');
// 在el之后插入
el.after(div, span);
// 在el之前插入
el.before(div, span);
删除节点
removeChild
JavaScript
const parent = document.querySelector('.container');
const child = parent.querySelector('.item');
// 通过父元素删除
parent.removeChild(child);
// 返回删除的节点
const removed = parent.removeChild(child);
remove
JavaScript
const el = document.querySelector('.item');
// 直接删除
el.remove();
replaceChild
JavaScript
const parent = document.querySelector('.container');
const newChild = document.createElement('div');
const oldChild = parent.querySelector('.item');
// 替换节点
parent.replaceChild(newChild, oldChild);
replaceWith
JavaScript
const el = document.querySelector('.item');
// 替换自身
el.replaceWith(document.createElement('div'));
克隆节点
cloneNode
JavaScript
const el = document.querySelector('.box');
// 浅克隆(只克隆元素,不含子节点)
const shallow = el.cloneNode();
// 深克隆(含所有子节点)
const deep = el.cloneNode(true);
// 注意:不克隆事件监听器
节点属性操作
属性读写
JavaScript
const el = document.querySelector('.box');
// 读取属性
el.getAttribute('class');
el.getAttribute('data-id');
// 设置属性
el.setAttribute('class', 'wrapper');
el.setAttribute('data-id', '123');
// 删除属性
el.removeAttribute('data-id');
// 检查属性是否存在
el.hasAttribute('data-id'); // true/false
// 获取所有属性
el.attributes; // NamedNodeMap
data属性
JavaScript
const el = document.querySelector('.box');
// dataset API
el.dataset.id = '123';
el.dataset.name = '张三';
console.log(el.dataset.id); // '123'
console.log(el.dataset.name); // '张三'
// HTML: data-id="123" data-name="张三"
innerHTML/outerHTML
innerHTML
JavaScript
const el = document.querySelector('.container');
// 设置内容(解析HTML)
el.innerHTML = '<div class="item">内容</div>';
// 获取内容
console.log(el.innerHTML);
// 清空内容
el.innerHTML = '';
outerHTML
JavaScript
const el = document.querySelector('.item');
// 获取(含自身)
console.log(el.outerHTML); // '<div class="item">内容</div>'
// 替换自身
el.outerHTML = '<span class="new">新内容</span>';
innerHTML安全问题
JavaScript
// 危险:用户输入直接innerHTML
el.innerHTML = userInput; // XSS风险
// 安全:使用textContent
el.textContent = userInput;
// 或转义后innerHTML
el.innerHTML = escapeHTML(userInput);
textContent vs innerText
text
const el = document.querySelector('.box');
// textContent:获取所有文本(含隐藏)
el.textContent;
// innerText:获取可见文本(受CSS影响)
el.innerText;
// 设置文本
el.textContent = '纯文本'; // 推荐
el.innerText = '纯文本';
| 特性 | textContent | innerText |
|---|---|---|
| 性能 | 更快 | 较慢 |
| 隐藏文本 | 包含 | 不包含 |
| CSS影响 | 不受影响 | 受影响 |
| 推荐 | 推荐 | 特定场景 |
要点总结
- DocumentFragment:批量操作优化,减少重排
- cloneNode(true):深克隆含子节点
- insertBefore:精确控制插入位置
- innerHTML风险:避免XSS,用textContent
- textContent推荐:性能更好,不受CSS影响
📝 发现内容有误?点击此处直接编辑