JavaScript DOM操作实例:怎么获取元素、修改样式及绑定事件

作者:像素漫游

时间:2026-10-30

浏览:243

深入浅出讲解JavaScript DOM操作的核心方法,包括现代与传统元素获取API对比、内联样式与classList修改方式选择、addEventListener事件绑定及事件委托实战。

文章目录

在网页前端交互开发中,DOM(文档对象模型,Document Object Model)是 JavaScript 操作 HTML 结构的桥梁。无论网页功能多么复杂,绝大多数页面交互的核心链路都可以归纳为三步:先定位到页面中的目标节点,接着改变其内容或外观样式,最后为它赋予响应用户点击、悬浮等动作的事件监听。本文将紧扣这三个环节,通过具体代码与对比分析,系统讲解从元素抓取、样式调控到事件注册的实操方法与避坑要点。

一、精准定位:怎么在页面中获取元素

要把指令施加在按钮、输入框或文本上,首先需要在 JavaScript 中获取该元素的引用。现代浏览器提供了成熟且高效的 API 支持按 ID、类名、标签或 CSS 选择器获取节点。

1. 现代首选:querySelector 与 querySelectorAll

document.querySelector 和 document.querySelectorAll 支持传入任意合法的 CSS 选择器,语法灵活直观,是目前前端开发中使用最广泛的抓取方式:

  • querySelector(selector):返回文档中匹配该选择器的第一个元素节点;若未找到则返回 null。
  • querySelectorAll(selector):返回包含所有匹配节点的静态 NodeList 集合;若无匹配则返回空列表(长度为 0)。
// 1. 获取 ID 为 submit-btn 的按钮
const submitBtn = document.querySelector('#submit-btn');

// 2. 获取包含 active 类名的首个卡片
const activeCard = document.querySelector('.card.active');

// 3. 获取列表中的所有选项节点集合
const menuItems = document.querySelectorAll('.nav-menu > li');
console.log(`共获取到 ${menuItems.length} 个导航项`);

2. 传统方法及其区别

在更早的规范中,常用的方法包括 document.getElementById('id')、document.getElementsByClassName('class') 以及 document.getElementsByTagName('tag')。它们具有极高的原生检索效率,但返回类型与选择器模式有所差异:

  • getElementById 直接接收纯 ID 字符串(无需加 # 前缀),返回单节点。
  • getElementsByClassName 返回的是动态 HTMLCollection。当页面 DOM 发生增删变化时,该集合会自动联动更新,而 querySelectorAll 返回的是静态快照(NodeList)。
JavaScript DOM操作实例:怎么获取元素、修改样式及绑定事件
图 1:DOM 树层级关系与常用元素获取 API 对应机制

避坑提示:NodeList 并不是纯数组
querySelectorAll 返回的是 NodeList。虽然它具有 forEach 方法与 length 属性,但它不具备 map()、filter() 等数组专属方法。如果需要使用高级数组操作,应先通过 Array.from(nodeList) 或展开语法 [...nodeList] 转为真实数组。

二、视觉重塑:怎么修改元素样式

获取到元素后,开发者常需调整尺寸、颜色、显隐等外观。在 JavaScript 中修改样式主要有两种途径:操作内联 style 属性,或者切换 CSS classList 类名。

1. 直接操作内联样式:element.style

每个 DOM 元素都有一个 style 对象属性。需要特别注意的是,CSS 属性中的中划线在 JavaScript 中必须转写为小驼峰命名(camelCase),且数值类属性通常需要显式指定单位:

const box = document.querySelector('#box');

// 正确示例:驼峰命名与带单位的字符串
box.style.backgroundColor = '#8A9478';
box.style.width = '300px';
box.style.marginTop = '20px';
box.style.display = 'block';

// 移除内联样式(恢复样式表规则)
box.style.backgroundColor = '';

2. 推荐规范:利用 classList 管理类名

在大型或规范项目中,直接写 element.style 会使样式规则分散在 JavaScript 代码中,不仅优先级过高难以覆盖,而且无法方便地复用 CSS 动画和过渡效果。更推荐的做法是将样式写在 CSS 类中,通过 classList API 动态增删:

  • classList.add('active', 'highlight'):添加一个或多个类名。
  • classList.remove('hidden'):移除指定类名。
  • classList.toggle('dark-mode'):切换类名(存在则删除,不存在则添加),非常适合做开关按钮。
  • classList.contains('is-open'):检测是否含有指定类名,返回布尔值。
  • classList.replace('old-class', 'new-class'):替换类名。
JavaScript DOM操作实例:怎么获取元素、修改样式及绑定事件
图 2:修改样式的两种路径特性对比与应用场景划分

三、赋予交互:怎么为元素绑定事件

网页的生动性取决于能够感知并响应用户的行为。无论是鼠标点击(click)、键盘敲击(keydown)还是表单提交(submit),都需要通过事件监听器与回调函数结合来实现。

1. 现代事件绑定的标准 API:addEventListener

相较于早期的 element.onclick = fn(后注册会直接覆盖先注册的函数),标准方法 addEventListener 支持为同一个事件类型挂载多个互不干扰的回调函数:

target.addEventListener(type, listener [, options]);

基本使用示例如下:

const btn = document.querySelector('#action-btn');

function handleClick(event) {
  // event.target 代表触发事件的具体目标元素
  console.log('按钮被点击了!当前时间戳:', event.timeStamp);
}

// 注册监听器
btn.addEventListener('click', handleClick);

// 如果需要注销监听,必须传入具有相同函数引用的具名函数:
// btn.removeEventListener('click', handleClick);

2. 事件流机制:捕获与冒泡

当用户在深层嵌套的子元素上点击时,事件并不是只在目标元素上触发,而是在 DOM 树中传播。事件流分为三个阶段:

  1. 捕获阶段(Capture Phase):事件从 window 和 document 逐级向下穿透,直至目标父节点。
  2. 目标阶段(Target Phase):事件抵达真正被点击的节点本身。
  3. 冒泡阶段(Bubbling Phase):事件由目标节点逐层向上传递回 document。

addEventListener 默认在冒泡阶段触发(第三个参数默认为 false)。

3. 高效性能实践:事件委托(Event Delegation)

如果有 100 个列表项(<li>),为每个 li 都单独绑定 addEventListener 会产生大量函数对象占用内存,且动态新增的 li 无法自动享有事件。借助事件冒泡,我们可以将监听器绑定在它们共同的父容器 <ul> 上,通过判断 event.target 来识别具体操作的目标:

const list = document.querySelector('#todo-list');

list.addEventListener('click', function(event) {
  // 检查真正被点击的元素是否是删除按钮
  if (event.target.classList.contains('delete-btn')) {
    const item = event.target.closest('li');
    item.remove();
  }
});
JavaScript DOM操作实例:怎么获取元素、修改样式及绑定事件
图 3:事件捕获/冒泡流向与父级事件委托架构运作原理

四、综合实例:交互式待办清单功能实现

为了让读者直观理解获取元素、修改样式与绑定事件的协同运作,下面给出一个完整的待办项交互小案例。它融合了前面讲到的三个环节:

<!-- 页面结构 -->
<div class="todo-app">
  <input type="text" id="task-input" placeholder="输入任务内容..." />
  <button id="add-btn">添加任务</button>
  <ul id="task-list"></ul>
</div>

<style>
  /* 预先在 CSS 中定义好完成状态的样式规则 */
  .completed {
    text-decoration: line-through;
    color: #999999;
    opacity: 0.7;
    transition: all 0.3s ease;
  }
  .task-item {
    display: flex;
    justify-content: space-between;
    padding: 8px 0;
    border-bottom: 1px dashed #E0E0E0;
  }
</style>

<script>
  // 1. 获取核心 DOM 节点
  const taskInput = document.querySelector('#task-input');
  const addBtn = document.querySelector('#add-btn');
  const taskList = document.querySelector('#task-list');

  // 2. 绑定添加按钮点击事件
  addBtn.addEventListener('click', function() {
    const text = taskInput.value.trim();
    if (!text) {
      alert('请输入任务内容!');
      return;
    }

    // 动态创建 li 元素并设置内容与基础类名
    const li = document.createElement('li');
    li.className = 'task-item';
    li.innerHTML = `
      <span class="task-text">${text}</span>
      <button class="del-btn">删除</button>
    `;

    // 挂载到 DOM 树中
    taskList.appendChild(li);
    taskInput.value = ''; // 清空输入框
  });

  // 3. 利用事件委托:在父级 ul 上同时处理“切换完成状态”与“删除任务”
  taskList.addEventListener('click', function(e) {
    // 如果点击的是任务文本,切换完成样式 (classList.toggle)
    if (e.target.classList.contains('task-text')) {
      e.target.classList.toggle('completed');
    }

    // 如果点击的是删除按钮,定位最近的 li 容器并移除
    if (e.target.classList.contains('del-btn')) {
      const parentLi = e.target.closest('li');
      if (parentLi) {
        parentLi.remove();
      }
    }
  });
</script>

五、全流程检查清单与常见错误排查

在实际编码中,很多突发异常都是由于对 DOM 加载时机、空指针防护或事件解绑规则了解不透彻造成的。以下是总结出的核心操作步骤闭环与防错核查清单:

JavaScript DOM操作实例:怎么获取元素、修改样式及绑定事件
图 4:JavaScript DOM 操作全链路自查与防错核对清单
异常现象 根本原因分析 针对性解决方案
Uncaught TypeError: Cannot read properties of null 执行 querySelector 时页面目标 DOM 尚未加载完成,或者选择器拼写错误。 将 <script> 标签移至 </body> 底部,或添加 defer 属性;并在操作前进行 if (element) { ... } 判空。
通过 element.style.color 获取不到设置的文字颜色 style 属性只能读取行内样式(直接写在标签上的 style="..."),读不到外部 CSS 样式表。 读取最终渲染样式应使用 window.getComputedStyle(element).color。
使用 removeEventListener 无法取消事件监听 绑定监听器时传入了匿名函数或箭头函数,每次调用都会生成全新的函数引用。 必须使用具名函数(声明命名的函数引用)进行注册与解绑,保持引用一致。
动态通过 JavaScript 新增的按钮点击无任何反应 在新增元素之前,监听器绑定代码就已经执行完毕,新增节点未绑定监听器。 改用事件委托,将事件监听器绑定在不变的静态父容器上。

综上所述,掌握 DOM 操作的关键在于理清节点获取的匹配规则、优先采用类名分离样式关注点,并依托事件流机制设计合理的监听与委托逻辑。在实际开发中养成判空保护、事件解绑和性能优化的编程习惯,能够显著提升代码的健壮性与可维护性。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章