跳到主要内容

JavaScript DOM 操作

DOM(Document Object Model,文档对象模型)是 JavaScript 操作网页的接口。

DOM 基础

什么是 DOM

DOM 将 HTML 文档解析为一个树形结构,每个 HTML 元素都是树上的一个节点。

document
├── html
│ ├── head
│ │ ├── title
│ │ └── meta
│ └── body
│ ├── header
│ ├── main
│ └── footer

DOM 树结构

  • 文档节点(Document):整个文档的入口
  • 元素节点(Element):HTML 标签
  • 文本节点(Text):标签内的文本
  • 属性节点(Attr):标签的属性
  • 注释节点(Comment):HTML 注释

获取元素

getElementById

通过 ID 获取单个元素:

const header = document.getElementById("header");
console.log(header);

getElementsByClassName

通过类名获取元素集合:

const buttons = document.getElementsByClassName("btn");
// 返回 HTMLCollection,需要用索引访问
console.log(buttons[0]);

getElementsByTagName

通过标签名获取元素集合:

const paragraphs = document.getElementsByTagName("p");
console.log(paragraphs.length);

querySelector

通过 CSS 选择器获取单个元素:

// 获取第一个匹配的元素
const nav = document.querySelector(".nav");
const submitBtn = document.querySelector("#submit-btn");
const firstListItem = document.querySelector("ul li");

querySelectorAll

通过 CSS 选择器获取所有匹配的元素:

const allLinks = document.querySelectorAll("a");
const cardItems = document.querySelectorAll(".card .item");

// 使用 forEach 遍历
allLinks.forEach(link => {
console.log(link.href);
});

DOM 元素操作

获取和设置内容

const element = document.querySelector("#title");

// 获取内容
console.log(element.textContent); // 获取所有文本
console.log(element.innerHTML); // 获取 HTML 内容

// 设置内容
element.textContent = "新标题";
element.innerHTML = "<span>新的</span> 标题";

// 区别:
// textContent 会转义 HTML 标签
// innerHTML 会解析 HTML 标签

获取和设置属性

const link = document.querySelector("a");

// 获取属性
console.log(link.getAttribute("href"));
console.log(link.href); // 完整 URL

// 设置属性
link.setAttribute("href", "https://example.com");
link.href = "https://example.com";

// 检查属性
console.log(link.hasAttribute("target")); // true/false

// 移除属性
link.removeAttribute("target");

// 设置布尔属性
input.disabled = true;
input.setAttribute("disabled", "");

class 操作

const box = document.querySelector(".box");

// 添加类
box.classList.add("active");
box.classList.add("highlight", "rounded");

// 移除类
box.classList.remove("active");
box.classList.remove("highlight", "rounded");

// 切换类(存在则移除,不存在则添加)
box.classList.toggle("active");

// 检查是否包含某个类
console.log(box.classList.contains("active")); // true/false

// 替换类
box.classList.replace("old-class", "new-class");

style 操作

const box = document.querySelector(".box");

// 设置单个样式
box.style.backgroundColor = "blue";
box.style.fontSize = "16px";

// 设置多个样式
Object.assign(box.style, {
color: "white",
padding: "20px",
borderRadius: "5px"
});

// 获取计算后的样式
const computedStyle = window.getComputedStyle(box);
console.log(computedStyle.backgroundColor);

data-* 属性

const card = document.querySelector(".card");

// 设置 data 属性
card.dataset.userId = "123";
card.dataset.role = "admin";

// 获取 data 属性
console.log(card.dataset.userId); // "123"
console.log(card.dataset.role); // "admin"

// 移除 data 属性
delete card.dataset.userId;

DOM 元素关系

父节点和子节点

const list = document.querySelector("ul");

// 父节点
const parent = list.parentNode;
const parentElement = list.parentElement;

// 子节点
const children = list.childNodes; // 包括文本节点
const childElements = list.children; // 只有元素节点
const firstChild = list.firstChild;
const lastChild = list.lastChild;
const firstElement = list.firstElementChild;
const lastElement = list.lastElementChild;

兄弟节点

const item = document.querySelector(".item");

// 前一个兄弟
const prev = item.previousSibling; // 包括文本节点
const prevElement = item.previousElementSibling;

// 后一个兄弟
const next = item.nextSibling; // 包括文本节点
const nextElement = item.nextElementSibling;

创建和删除元素

创建元素

// 创建新元素
const newDiv = document.createElement("div");
newDiv.textContent = "新创建的 div";
newDiv.className = "new-div";
newDiv.id = "unique-id";

// 创建文本节点
const textNode = document.createTextNode("这是文本");

// 创建文档片段(一次性添加到 DOM)
const fragment = document.createDocumentFragment();
for (let i = 0; i < 5; i++) {
const li = document.createElement("li");
li.textContent = `列表项 ${i + 1}`;
fragment.appendChild(li);
}
document.querySelector("ul").appendChild(fragment);

添加元素

const container = document.querySelector(".container");
const newElement = document.createElement("div");

// appendChild - 添加到末尾
container.appendChild(newElement);

// prepend - 添加到开头
container.prepend(newElement);

// before - 插入到元素之前
existingElement.before(newElement);

// after - 插入到元素之后
existingElement.after(newElement);

// insertAdjacentHTML
container.insertAdjacentHTML("beforeend", "<div>新元素</div>");
// beforebegin: 在元素前插入
// afterbegin: 在元素内开头插入
// beforeend: 在元素内末尾插入
// afterend: 在元素后插入

删除元素

const element = document.querySelector(".to-remove");

// 删除元素
element.remove();

// 或者通过父节点删除
element.parentNode.removeChild(element);

替换元素

const oldElement = document.querySelector(".old");
const newElement = document.createElement("div");
newElement.textContent = "新元素";

oldElement.replaceWith(newElement);
// 或者
oldElement.parentNode.replaceChild(newElement, oldElement);

元素尺寸和位置

offset 系列

const box = document.querySelector(".box");

console.log(box.offsetParent); // 定位祖先元素
console.log(box.offsetTop); // 距定位祖先的顶部距离
console.log(box.offsetLeft); // 距定位祖先的左侧距离
console.log(box.offsetWidth); // width + padding + border
console.log(box.offsetHeight); // height + padding + border

client 系列

console.log(box.clientTop);       // border 宽度
console.log(box.clientLeft); // border 宽度
console.log(box.clientWidth); // width + padding(不含 border)
console.log(box.clientHeight); // height + padding(不含 border)

scroll 系列

console.log(box.scrollTop);       // 已滚动上去的像素
console.log(box.scrollLeft); // 已滚动左边的像素
console.log(box.scrollWidth); // 内容的总宽度
console.log(box.scrollHeight); // 内容的总高度

getBoundingClientRect

const rect = box.getBoundingClientRect();

console.log(rect.x); // 元素左边相对于视口的坐标
console.log(rect.y); // 元素顶部相对于视口的坐标
console.log(rect.width); // 元素宽度(包含 border)
console.log(rect.height); // 元素高度(包含 border)
console.log(rect.top); // 元素上边距视口顶部的距离
console.log(rect.bottom); // 元素下边距视口顶部的距离
console.log(rect.left); // 元素左边距视口左边的距离
console.log(rect.right); // 元素右边距视口左边的距离

实战案例

留言板功能

const messageInput = document.querySelector("#message-input");
const submitBtn = document.querySelector("#submit-btn");
const messageList = document.querySelector("#message-list");

submitBtn.addEventListener("click", () => {
const message = messageInput.value.trim();
if (!message) {
alert("请输入留言内容");
return;
}

const messageItem = document.createElement("div");
messageItem.className = "message-item";
messageItem.innerHTML = `
<p class="message-text">${escapeHtml(message)}</p>
<button class="delete-btn">删除</button>
`;

messageList.appendChild(messageItem);
messageInput.value = "";

messageItem.querySelector(".delete-btn").addEventListener("click", () => {
messageItem.remove();
});
});

function escapeHtml(text) {
const div = document.createElement("div");
div.textContent = text;
return div.innerHTML;
}

回到顶部

const backToTopBtn = document.querySelector("#back-to-top");

window.addEventListener("scroll", () => {
if (window.scrollY > 300) {
backToTopBtn.style.display = "block";
} else {
backToTopBtn.style.display = "none";
}
});

backToTopBtn.addEventListener("click", () => {
window.scrollTo({
top: 0,
behavior: "smooth"
});
});

小结

  1. DOM 将 HTML 文档解析为树形结构
  2. 通过选择器(getElementById、querySelector 等)获取元素
  3. 操作元素的内容、属性、样式
  4. 创建、添加、删除 DOM 元素
  5. 获取元素的尺寸和位置信息

练习

  1. 实现一个待办事项列表(添加、完成、删除)
  2. 实现图片懒加载功能
  3. 实现一个简单的轮播图组件
  4. 实现表格的全选、反选功能