5个JavaScript迷你项目实战,快速掌握DOM操作基础

作者:像素猫时间:2026-10-30 19:07:43浏览:381

通过点击计数器、待办清单、实时字数统计、手风琴折叠面板与模态弹窗5个典型实战项目,循序渐进掌握元素选择、事件绑定、节点创建、样式切换与事件冒泡等DOM核心操作。

掌握文档对象模型(DOM)是前端交互开发的基石。本文通过点击计数器、待办清单、实时字数统计器、手风琴折叠面板与模态弹窗5个轻量项目,按照“元素选择、事件绑定、状态变更、视图更新”的实际链路,带你系统建立DOM操作的核心心智模型与代码直觉。

一、DOM树与JavaScript交互原理

当浏览器解析HTML文档时,会将其构建为一个由节点构成的树状结构——DOM树。JavaScript本身并不具备渲染网页画面的能力,它必须通过浏览器提供的DOM API(如 document.querySelector、addEventListener 等)作为桥梁,读取页面上的标签属性、监听用户行为并实时修改结构或内容。

初学者常犯的错误是将界面状态直接与HTML文本强耦合,导致代码在修改多个地方时出现遗漏。理解DOM的关键在于把握“状态驱动界面”的思想:用户的每一次点击或输入,先触发JavaScript事件处理函数,更新内部数据变量,最后再将计算后的最新结果同步给DOM节点。

5个JavaScript迷你项目实战,快速掌握DOM操作基础
图 1:DOM 树形架构与 JavaScript 操作 API 映射拓扑

二、项目一:点击计数器(Counter)

点击计数器是理解“元素获取、事件监听、数据状态同步”的最经典案例。我们在此项目中练习如何读取一个数字、响应加减与重置按钮,并更新界面文本。

1. 核心HTML结构

<div class="counter-box">
  <h3 id="count-display">0</h3>
  <button id="btn-decrease">-1</button>
  <button id="btn-reset">重置</button>
  <button id="btn-increase">+1</button>
</div>

2. JavaScript 实现

// 1. 获取需要操作的 DOM 节点
const countDisplay = document.querySelector('#count-display');
const btnDecrease = document.querySelector('#btn-decrease');
const btnReset = document.querySelector('#btn-reset');
const btnIncrease = document.querySelector('#btn-increase');

// 2. 维护独立的状态变量,避免从 DOM 中反向读取字符串
let count = 0;

// 3. 封装渲染函数:让界面严格反映当前状态
function updateDisplay() {
  countDisplay.textContent = count;
  // 根据数值正负变化显示样式
  if (count > 0) {
    countDisplay.style.color = '#71A397';
  } else if (count < 0) {
    countDisplay.style.color = '#E06C75';
  } else {
    countDisplay.style.color = '#1E293B';
  }
}

// 4. 为每个按钮绑定独立的点击事件处理程序
btnIncrease.addEventListener('click', () => {
  count += 1;
  updateDisplay();
});

btnDecrease.addEventListener('click', () => {
  count -= 1;
  updateDisplay();
});

btnReset.addEventListener('click', () => {
  count = 0;
  updateDisplay();
});
注意事项:为什么使用 textContent 而不是 innerHTML?因为计数器只包含纯文本内容。使用 innerHTML 会触发浏览器的 HTML 解析器,既消耗多余性能,又在面对不受信数据时存在潜在的 XSS 安全风险。

三、项目二:简易待办清单(Todo List)

待办清单的核心是学习“动态生成新节点(createElement)”、“挂载到父节点(appendChild)”以及“节点销毁(remove)”。此外,项目还涉及表单默认提交行为的拦截。

1. 核心HTML结构

<form id="todo-form">
  <input type="text" id="todo-input" placeholder="输入待办事项并回车..." required />
  <button type="submit">添加</button>
</form>
<ul id="todo-list"></ul>

2. JavaScript 实现

const todoForm = document.querySelector('#todo-form');
const todoInput = document.querySelector('#todo-input');
const todoList = document.querySelector('#todo-list');

todoForm.addEventListener('submit', (e) => {
  // 阻止表单提交引起的页面刷新
  e.preventDefault();

  const text = todoInput.value.trim();
  if (text === '') return;

  // 1. 创建列表外层 li 元素
  const li = document.createElement('li');
  li.className = 'todo-item';

  // 2. 创建文本描述 span
  const textSpan = document.createElement('span');
  textSpan.textContent = text;

  // 点击文本完成/取消标记
  textSpan.addEventListener('click', () => {
    textSpan.classList.toggle('completed');
  });

  // 3. 创建删除按钮
  const delBtn = document.createElement('button');
  delBtn.textContent = '删除';
  delBtn.className = 'btn-delete';
  delBtn.addEventListener('click', () => {
    li.remove(); // 销毁整个 li 节点
  });

  // 4. 组装并挂载到待办列表中
  li.appendChild(textSpan);
  li.appendChild(delBtn);
  todoList.appendChild(li);

  // 5. 清空输入框并重新聚焦
  todoInput.value = '';
  todoInput.focus();
});
5个JavaScript迷你项目实战,快速掌握DOM操作基础
图 2:DOM 节点创建、属性配置与挂载流程步骤

四、项目三:实时字数统计器(Character Counter)

这个项目展示了如何响应连续的高频用户输入(input 事件),并依据剩余字数动态更新界面的文字与警告样式。

1. 核心HTML结构

<div class="char-box">
  <textarea id="text-input" placeholder="请输入内容,限100字以内..." maxlength="100"></textarea>
  <div class="counter-status">
    已输入 <span id="char-current">0</span> / <span id="char-max">100</span> 字
    <span id="warning-msg" style="display: none; color: #E06C75;">已达到上限!</span>
  </div>
</div>

2. JavaScript 实现

const textInput = document.querySelector('#text-input');
const charCurrent = document.querySelector('#char-current');
const warningMsg = document.querySelector('#warning-msg');
const MAX_LENGTH = 100;

// 使用 'input' 事件:只要输入框内容发生变化(包括粘贴、打字、删除)便立即触发
textInput.addEventListener('input', () => {
  const currentLength = textInput.value.length;
  
  // 更新当前计数字符
  charCurrent.textContent = currentLength;

  // 根据字数动态切换警告状态
  if (currentLength >= MAX_LENGTH) {
    warningMsg.style.display = 'inline';
    charCurrent.style.color = '#E06C75';
    textInput.style.borderColor = '#E06C75';
  } else if (currentLength >= MAX_LENGTH * 0.8) {
    warningMsg.style.display = 'none';
    charCurrent.style.color = '#D19A66';
    textInput.style.borderColor = '#D19A66';
  } else {
    warningMsg.style.display = 'none';
    charCurrent.style.color = '#64748B';
    textInput.style.borderColor = '#CBD5E1';
  }
});
关键对比:监听文本框时,change 事件只有在输入框失去焦点时才会触发,而 input 事件在每一次按键、拼音确认或粘贴时都会实时触发。实现“即时反馈”功能时,必须优先选择 input 事件。

五、项目四:手风琴折叠面板(Accordion)

手风琴组件是前端最常见的交互模式之一。在这个实战中,我们将掌握通过 querySelectorAll 选取节点列表、遍历绑定事件、读取数据属性以及实现排他展开(即展开当前项时自动折叠其他项)。

1. 核心HTML结构

<div class="accordion">
  <div class="accordion-item">
    <button class="accordion-header">什么是 DOM?</button>
    <div class="accordion-content">DOM 是文档对象模型,是 HTML 文档的编程接口。</div>
  </div>
  <div class="accordion-item">
    <button class="accordion-header">什么是事件委托?</button>
    <div class="accordion-content">利用事件冒泡机制,将子元素事件委托给父容器统一监听。</div>
  </div>
</div>

2. JavaScript 实现

const headers = document.querySelectorAll('.accordion-header');

headers.forEach((header) => {
  header.addEventListener('click', () => {
    const currentItem = header.parentElement;
    const isActive = currentItem.classList.contains('active');

    // 1. 排他处理:先关闭所有已展开的项目
    document.querySelectorAll('.accordion-item').forEach((item) => {
      item.classList.remove('active');
    });

    // 2. 如果之前未展开,则激活当前项;反之保持关闭
    if (!isActive) {
      currentItem.classList.add('active');
    }
  });
});
5个JavaScript迷你项目实战,快速掌握DOM操作基础
图 3:DOM 事件冒泡原理与委托监听机制对比

六、项目五:模态框弹窗(Modal Popup)

模态弹窗涉及界面层级显示、键盘全局事件捕获(按 ESC 键退出)以及事件冒泡阻断。这是综合性最强的基础实战之一。

1. 核心HTML结构

<button id="open-modal-btn">打开弹窗</button>

<!-- 模态框全屏遮罩 -->
<div id="modal-overlay" class="modal-overlay hidden">
  <div class="modal-card">
    <h4>重要系统提示</h4>
    <p>这是一个使用纯原生 JavaScript 控制的模态弹窗组件。</p>
    <button id="close-modal-btn">关闭</button>
  </div>
</div>

2. JavaScript 实现

const openModalBtn = document.querySelector('#open-modal-btn');
const closeModalBtn = document.querySelector('#close-modal-btn');
const modalOverlay = document.querySelector('#modal-overlay');
const modalCard = document.querySelector('.modal-card');

function openModal() {
  modalOverlay.classList.remove('hidden');
}

function closeModal() {
  modalOverlay.classList.add('hidden');
}

// 1. 点击打开按钮显示弹窗
openModalBtn.addEventListener('click', openModal);

// 2. 点击弹窗内部关闭按钮关闭
closeModalBtn.addEventListener('click', closeModal);

// 3. 点击遮罩背景关闭弹窗
modalOverlay.addEventListener('click', (e) => {
  // 仅当点击的是遮罩自身时关闭,避免点击内容卡片误关闭
  if (e.target === modalOverlay) {
    closeModal();
  }
});

// 4. 监听全局键盘事件:按下 ESC 键退出
document.addEventListener('keydown', (e) => {
  if (e.key === 'Escape' && !modalOverlay.classList.contains('hidden')) {
    closeModal();
  }
});
避坑指南:在处理遮罩点击关闭时,如果为弹窗内部的内容卡片添加了点击处理,点击卡片可能会因为事件冒泡(Event Bubbling)冒泡到遮罩上,导致弹窗意外关闭。通过 e.target === modalOverlay 的严格等值判断,或者在内容卡片上调用 e.stopPropagation(),可以有效解决此问题。

七、5个实战项目技能全景图谱

每个项目都聚焦于特定的核心能力。下表将5个迷你项目与DOM核心操作能力进行了完整归纳:

5个JavaScript迷你项目实战,快速掌握DOM操作基础
图 4:5个迷你项目核心 DOM 技能掌握知识全景图谱

八、总结与进阶建议

通过这5个小项目,我们掌握了DOM操作的基础语法体系:

  • 选择精准化:优先使用标准 CSS 选择器 querySelector 和 querySelectorAll,语义更清晰统一。
  • 状态优先:业务逻辑中的数字、列表数组和布尔开关应作为 JavaScript 内存变量维护,而非直接从 DOM 节点的文本中来回截取。
  • 样式解耦:通过 classList.add()、classList.remove() 和 classList.toggle() 管理 CSS 类名,避免在 JS 中直接拼接复杂的内联样式字符串。
  • 善用委托:对于包含大量子项或动态新增项的列表,将事件委托到父容器可以大幅降低内存消耗并简化生命周期管理。

动手在本地编辑器中敲一遍上述代码并尝试为其添加新特性(例如为待办事项增加本地存储 localStorage 持久化),是快速巩固原生 DOM 能力最扎实的路径。

作者最新文章
相关文章
更多