JavaScript 的 DOM 操作

什么是 DOM?

想象一下你的一个 HTML 网页文件。它里面有很多标签,比如 <html>, <body>, <h1>, <p>, <div> 等等。这些标签不是孤立的,它们之间有层级关系,比如 <h1><body> 里面,<body><html> 里面。

DOM (Document Object Model,文档对象模型) 就是浏览器为这个 HTML 文档在内存中创建的一个树形结构。它把整个文档的每一个部分(元素、属性、文本等)都看作是一个“对象”或“节点”。

通过 JavaScript,我们可以访问和操作这个树形结构中的任何一个节点,从而动态地改变网页的内容、结构和样式。简单来说:

DOM 是连接 HTML 页面和 JavaScript 语言的一座桥梁。

JavaScript 对网页的所有修改,实际上都是通过修改 DOM 树的节点来完成的。当 DOM 树被修改后,浏览器会自动重新渲染页面,向用户展示更新后的内容。


第一步:获取(选中)DOM 元素

要操作一个元素,首先你得能找到它。这就像你想跟某人说话,你得先知道他在哪里。JavaScript 提供了多种方法来“选中”页面上的元素。

假设我们有以下 HTML 代码:

<!DOCTYPE html>
<html>
<head>
    <title>DOM 学习</title>
</head>
<body>
    <h1 id="main-title">欢迎学习 DOM</h1>
    <p class="content">这是一个段落。</p>
    <p class="content">这是另一个段落。</p>
    <div>
        <a href="#">链接1</a>
        <a href="#">链接2</a>
    </div>
</body>
</html>

1. 通过 ID 获取 (最常用,最快)

ID 在一个页面中应该是唯一的。这是选中特定元素最精确、最高效的方法。

  • 方法: document.getElementById('你的ID')
  • 返回: 一个单独的元素对象。如果找不到,返回 null
// 选中 ID 为 main-title 的 h1 元素
const titleElement = document.getElementById('main-title');

console.log(titleElement); // 会输出 <h1>...</h1> 这个元素对象

2. 通过 Class 名称获取

一个页面中可以有很多元素使用相同的 class。这个方法会把所有符合条件的元素都找出来。

  • 方法: document.getElementsByClassName('你的Class名')
  • 返回: 一个 HTMLCollection (HTML集合),它像一个数组,包含了所有匹配的元素。
// 选中所有 class 为 content 的元素
const contentParagraphs = document.getElementsByClassName('content');

console.log(contentParagraphs); // 会输出一个包含两个 <p> 元素的 HTMLCollection
console.log(contentParagraphs[0]); // 可以像数组一样访问第一个 <p>
console.log(contentParagraphs[1]); // 访问第二个 <p>

3. 通过标签名 (Tag Name) 获取

这会选中页面上所有指定类型的标签。

  • 方法: document.getElementsByTagName('标签名')
  • 返回: 一个 HTMLCollection
// 选中所有的 <a> 标签
const allLinks = document.getElementsByTagName('a');

console.log(allLinks); // 输出包含两个 <a> 元素的 HTMLCollection

4. 通过 CSS 选择器获取 (现代、强大且灵活)

这是现代 JavaScript 中最推荐的方法,因为它像写 CSS 一样方便,几乎可以选中任何你想要的元素。

a) 选中第一个匹配的元素
  • 方法: document.querySelector('你的CSS选择器')
  • 返回: 匹配到的第一个元素对象。如果找不到,返回 null
// 通过 ID 选择器
const title = document.querySelector('#main-title');

// 通过 class 选择器 (只会选中第一个)
const firstContent = document.querySelector('.content');

// 通过标签选择器
const firstLink = document.querySelector('a');

// 通过更复杂的后代选择器
const firstLinkInDiv = document.querySelector('div a');
b) 选中所有匹配的元素
  • 方法: document.querySelectorAll('你的CSS选择器')
  • 返回: 一个 NodeList (节点列表),它也像一个数组,包含了所有匹配的元素。
// 选中所有 class 为 content 的段落
const allContents = document.querySelectorAll('.content');

// 选中 div 里的所有 a 标签
const allLinksInDiv = document.querySelectorAll('div a');

// 遍历所有选中的元素
allLinksInDiv.forEach(function(link) {
    console.log(link); // 会依次打印出每个 <a> 元素
});

小结:

  • 要精确选中一个元素,用 getElementByIdquerySelector
  • 要选中一组元素,用 getElementsByClassName, getElementsByTagNamequerySelectorAll
  • querySelectorquerySelectorAll 是最现代和灵活的方法,建议优先使用。

第二步:修改 DOM 元素

一旦你用上面的方法选中了元素并存到了一个变量里,你就可以开始对它为所欲为了。

1. 修改元素内容

  • innerHTML: 获取或设置一个元素内部的 HTML 内容
  • textContent: 获取或设置一个元素内部的 纯文本内容
const titleElement = document.getElementById('main-title');

// 读取内容
console.log(titleElement.innerHTML);   // 输出 "欢迎学习 DOM"
console.log(titleElement.textContent); // 输出 "欢迎学习 DOM"

// 修改内容
// titleElement.innerHTML = '<i>JavaScript</i> DOM 操作'; // <i> 标签会被解析
titleElement.textContent = 'JavaScript DOM 操作';     // 更安全、高效,不会解析 HTML 标签

安全提示: 尽量使用 textContent。如果你使用 innerHTML 来插入用户提供的内容,可能会导致 XSS (跨站脚本) 攻击,因为恶意用户可能会输入 <script> 标签来执行危险代码。

2. 修改元素属性

比如修改图片的 src、链接的 href 等。

  • 直接访问属性: 元素.属性名 (例如 img.src)
  • 通用方法: 元素.getAttribute('属性名')元素.setAttribute('属性名', '新值')
const link = document.querySelector('a'); // 选中第一个 a 标签

// 读取 href 属性
console.log(link.href);

// 修改 href 属性
link.setAttribute('href', 'https://www.google.com');
link.textContent = '前往 Google'; // 把文字也改一下

3. 修改元素样式 (CSS)

你可以直接修改元素的行内样式。

  • 方法: 元素.style.样式属性 = '值'

注意: CSS 属性名在 JavaScript 中需要写成驼峰式命名 (camelCase)。例如 background-color 要写成 backgroundColorfont-size 要写成 fontSize

const titleElement = document.getElementById('main-title');

// 修改样式
titleElement.style.color = 'blue';
titleElement.style.backgroundColor = '#f0f0f0'; // CSS 的 background-color
titleElement.style.fontSize = '32px';         // CSS 的 font-size
titleElement.style.padding = '10px';

4. 修改元素的 Class

动态地添加或移除 class 是控制元素样式的最佳实践(比直接修改 style 更好)。

  • 方法: 元素.classList,它提供了一些方便的方法:
    • add('className'): 添加一个 class。
    • remove('className'): 移除一个 class。
    • toggle('className'): 如果 class 存在则移除,不存在则添加。
    • contains('className'): 检查是否存在某个 class,返回 truefalse
// 假设 CSS 文件里有一个 .highlight 类
// .highlight { color: red; font-weight: bold; }

const p = document.querySelector('.content');

// 添加 class
p.classList.add('highlight');

// 移除 class
// p.classList.remove('content');

// 切换 class (如果已有 highlight 就移除,没有就加上)
p.classList.toggle('highlight');

第三步:创建、添加和删除元素

这部分是让你的网页“活”起来的关键,你可以根据需要动态地增加或减少页面内容。

1. 创建新元素

首先,我们需要在 JavaScript 的“世界”里(内存中)创建一个新的 HTML 元素。这个元素被创建后,还不在页面上,像一个还没登场的演员。

  • 方法: document.createElement('标签名')
// 创建一个新的 <div> 元素
const newDiv = document.createElement('div');

// 创建一个新的 <img> 元素
const newImage = document.createElement('img');

// 创建一个新的列表项 <li>
const newItem = document.createElement('li');

创建好元素后,你可以像操作普通元素一样,给它添加内容、样式或属性。

// 给新创建的 li 添加文本内容
newItem.textContent = '我是新来的列表项';

// 给它添加一个 class
newItem.classList.add('list-item');

// 给新创建的图片设置 src 和 alt 属性
newImage.src = 'https://via.placeholder.com/150'; // 使用一个占位图
newImage.alt = '占位图片';

2. 添加元素到页面中

演员准备好了,现在要让他登台。你需要指定一个“父元素”(舞台),然后把新创建的元素添加进去。

a) 添加到父元素的末尾 (最常用)
  • 现代方法: 父元素.append(新元素)
  • 传统方法: 父元素.appendChild(新元素)

append() 更现代,功能也更强大(比如可以一次添加多个元素),推荐使用。

// 假设页面上已经有一个 <ul> 元素
// <ul id="my-list"><li>列表项1</li></ul>

// 1. 先选中父元素
const list = document.querySelector('#my-list');

// 2. 将我们上面创建的 newItem 添加进去
list.append(newItem);

执行后,HTML 就会变成:

<ul id="my-list">
    <li>列表项1</li>
    <li class="list-item">我是新来的列表项</li> </ul>
b) 添加到父元素的开头
  • 现代方法: 父元素.prepend(新元素)
const list = document.querySelector('#my-list');
list.prepend(newItem); // newItem 会被加到列表项1的前面

3. 删除元素

当某个元素不再需要时,我们可以将它从 DOM 树中移除。

  • 现代方法 (极其简单): 要删除的元素.remove()

这是最直接、最方便的方式。

// 假设我们要删除刚才添加的 newItem
// 首先,你需要能选中它,如果之前没有存到变量里的话
const itemToRemove = document.querySelector('.list-item'); // 假设我们这样能选中它

// 直接调用 remove()
if (itemToRemove) { // 最好先判断一下元素是否存在
    itemToRemove.remove();
}
  • 传统方法: 父元素.removeChild(要删除的子元素)

这个方法需要先获取到父元素,比较繁琐。

const parentList = itemToRemove.parentElement; // 先找到它的父元素
parentList.removeChild(itemToRemove); // 再通过父元素来删除它

显然,直接使用 .remove() 要简单得多。


第四步:响应用户交互 (事件处理)

静态的页面是不够的,我们需要对用户的行为(如点击、滚动、按键等)做出反应。这些行为在 JavaScript 中被称为 事件 (Events)

我们可以为元素“绑定”一个 事件监听器 (Event Listener),它会一直“监听”某个特定事件,一旦事件发生,就执行我们预先定义好的函数。

1. 如何监听事件

  • 核心方法: 元素.addEventListener('事件类型', '要执行的函数')

这是处理事件的标准方式,非常强大。

  • 事件类型: 一个字符串,表示你想监听哪种事件。常用事件有:
    • click: 用户单击。
    • mouseover: 鼠标指针移入元素。
    • mouseout: 鼠标指针移出元素。
    • keydown: 用户按下键盘上的任意键。
    • keyup: 用户释放键盘上的按键。
    • submit: 用户提交表单。
  • 要执行的函数: 也称为回调函数 (Callback Function)事件处理器 (Event Handler)。当事件发生时,这个函数就会被自动调用。

2. click 事件示例

我们来做一个最经典的例子:点击一个按钮,然后改变页面上的一些文字。

<button id="my-button">点我!</button>
<p id="status-text">请点击按钮。</p>
// 1. 选中需要操作的元素
const btn = document.getElementById('my-button');
const statusText = document.getElementById('status-text');

// 2. 为按钮添加一个点击事件监听器
btn.addEventListener('click', function() {
    // 这个匿名函数里的代码,只有在按钮被点击时才会执行
    console.log('按钮被点击了!');
    statusText.textContent = '恭喜!你成功触发了事件!';
    statusText.style.color = 'green';
});

现在,每次你点击这个按钮,<p> 标签里的文字和颜色都会改变。

3. 事件对象 (Event Object)

当事件发生时,浏览器会自动创建一个包含该事件所有信息的事件对象,并把它作为第一个参数传递给你的回调函数。我们通常用 eventevte 来命名这个参数。

这个对象非常有用,它包含了比如“是谁触发了事件”、“鼠标点击的位置”等信息。

  • event.target: 这是事件对象中最重要的属性之一,它指向真正触发事件的那个元素

我们来看一个例子,当鼠标悬浮在不同的列表项上时,高亮显示该列表项。

HTML:

<ul id="color-list">
    <li>红色</li>
    <li>绿色</li>
    <li>蓝色</li>
</ul>

JavaScript:

const colorList = document.getElementById('color-list');

// 我们把事件监听器绑定在整个 <ul> 上,而不是每个 <li>
colorList.addEventListener('mouseover', function(event) {
    // event.target 就是当前鼠标所在的那个 <li>
    const targetLi = event.target;
    
    // 确保我们操作的是 li 元素,而不是 ul 本身
    if (targetLi.tagName === 'LI') {
        targetLi.style.backgroundColor = 'yellow';
    }
});

// 监听鼠标移出事件,用于恢复背景色
colorList.addEventListener('mouseout', function(event) {
    if (event.target.tagName === 'LI') {
        event.target.style.backgroundColor = ''; // 恢复默认背景
    }
});

这种将事件监听器绑定在父元素上,利用 event.target 来管理子元素事件的技术,被称为事件委托 (Event Delegation),是一种非常高效的模式。

  • event.preventDefault(): 这个方法可以阻止事件的默认行为。例如,阻止点击一个链接后跳转页面,或者阻止提交一个表单后刷新页面。
const myLink = document.querySelector('a'); // 假设页面有个链接

myLink.addEventListener('click', function(event) {
    // 阻止链接的默认跳转行为
    event.preventDefault(); 
    
    console.log('链接跳转被我阻止了!');
});

通过掌握元素的增删改查和事件处理,你就具备了用 JavaScript 彻底掌控一个网页的能力,可以创造出丰富、动态、高交互性的用户体验。