在前端开发中,动态表格是一个非常基础且高频的需求,比如后台管理系统的列表操作、数据展示页面的行管理等。本文将带大家从零开始,使用原生 JavaScript实现一个支持行添加、行删除、隔行变色的动态表格,全程不依赖任何框架,深入理解 DOM 操作与事件处理的核心逻辑。
一、需求分析
我们需要实现的动态表格具备以下功能:
- 点击 “按钮” 新增一行数据,序号自动递增,数字以 100 为步长累加;
- 点击每行的 “删除” 按钮,移除当前行;
- 表格自动实现隔行变色效果,且删除行后样式自动重新校准;
- 全程使用原生 DOM 操作,不拼接 HTML 字符串,保证代码安全性与可维护性。
二、技术选型与核心原理
1. 技术选型
- HTML:搭建表格的基础结构,使用
<thead>定义表头,<tbody>承载动态行; - CSS:定义隔行变色的样式类,通过类名的添加 / 移除实现样式切换;
- 原生 JavaScript:
- DOM 创建:
document.createElement()动态生成行、单元格、按钮; - DOM 操作:
appendChild()实现节点的层级挂载; - 事件委托:利用事件冒泡机制,给
<tbody>绑定点击事件,处理删除逻辑; - 样式控制:
classList.add()/classList.remove()操作元素类名。
- DOM 创建:
2. 核心原理
- 动态创建 DOM 节点:不使用
innerHTML拼接 HTML,而是通过createElement创建<tr>、<td>、<button>等节点,再通过appendChild挂载到父节点上,避免 XSS 风险; - 事件委托:删除按钮是动态生成的,无法直接绑定事件,因此给父元素
<tbody>绑定点击事件,通过事件对象e.target判断点击的是否为删除按钮,实现动态元素的事件处理; - 样式重绘:每次新增或删除行后,重新遍历所有行,根据行的索引重新计算并设置隔行变色样式,保证样式始终正确。
三、完整代码实现
1. HTML 结构
html
预览
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>原生JS动态表格</title> <style> table { border-collapse: collapse; margin-top: 10px; width: 400px; } th, td { border: 1px solid #333; padding: 8px 12px; text-align: center; } .blue-bg { background-color: #cce5ff; } button { padding: 4px 8px; cursor: pointer; } </style> </head> <body> <button onclick="selectAll()">新增行</button> <table class="student"> <thead> <tr> <th>序号</th> <th>数字</th> <th>操作</th> </tr> </thead> <tbody> <!-- 动态行将插入这里 --> </tbody> </table> <script> // 初始化序号与数字 let currentIndex = 0; let num = 100; /** * 新增行函数 */ function selectAll() { // 1. 获取tbody容器 const tbody = document.querySelector('tbody'); // 2. 创建tr行节点 const tr = document.createElement('tr'); // 3. 创建序号单元格 const tdIndex = document.createElement('td'); tdIndex.textContent = currentIndex + 1; tr.appendChild(tdIndex); // 4. 创建数字单元格 const tdNum = document.createElement('td'); num += 100; tdNum.textContent = num; tr.appendChild(tdNum); // 5. 创建操作单元格(包含删除按钮) const tdWork = document.createElement('td'); const delBtn = document.createElement('button'); delBtn.textContent = '删除'; tdWork.appendChild(delBtn); tr.appendChild(tdWork); // 6. 将行添加到tbody tbody.appendChild(tr); // 7. 更新序号 currentIndex++; // 8. 重新渲染隔行变色 renderRowStyle(); } /** * 事件委托 - 处理删除逻辑 */ document.querySelector('.student tbody').addEventListener('click', function(e) { // 判断点击的是否为删除按钮 if (e.target.tagName === 'BUTTON' && e.target.textContent === '删除') { // 获取当前行并移除 const targetTr = e.target.parentElement.parentElement; targetTr.remove(); // 重新渲染隔行变色 renderRowStyle(); } }); /** * 渲染隔行变色样式 */ function renderRowStyle() { // 获取所有行 const trList = document.querySelectorAll('tbody tr'); // 遍历所有行,重置样式并重新设置 for (let i = 0; i < trList.length; i++) { trList[i].classList.remove('blue-bg'); // 偶数行(索引+1为偶数)添加蓝色背景 if ((i + 1) % 2 === 0) { trList[i].classList.add('blue-bg'); } } } </script> </body> </html>2. 代码分模块解析
(1)HTML 与 CSS 部分
- HTML 结构:使用
<table>标签搭建表格,<thead>定义表头的 “序号、数字、操作” 三列,<tbody>用于承载动态生成的行; - CSS 样式:
border-collapse: collapse合并表格边框,让表格更美观;.blue-bg类定义隔行变色的背景色;- 给按钮、单元格添加内边距和居中样式,提升用户体验。
(2)JavaScript 部分
初始化变量
javascript
运行
let currentIndex = 0; // 记录当前序号 let num = 100; // 记录初始数字两个变量分别用于控制新增行的序号递增和数字累加。
新增行函数
selectAll()- 步骤 1:获取
<tbody>容器,作为动态行的父节点; - 步骤 2:通过
document.createElement()依次创建<tr>行、<td>单元格、<button>删除按钮; - 步骤 3:使用
textContent设置单元格和按钮的文本内容,数字以 100 为步长累加; - 步骤 4:通过
appendChild()将子节点依次挂载到父节点上,形成tbody → tr → td的层级结构; - 步骤 5:调用
renderRowStyle()函数,重新渲染隔行变色样式。
- 步骤 1:获取
事件委托实现删除功能
javascript
运行
document.querySelector('.student tbody').addEventListener('click', function(e) { if (e.target.tagName === 'BUTTON' && e.target.textContent === '删除') { const targetTr = e.target.parentElement.parentElement; targetTr.remove(); renderRowStyle(); } });- 核心逻辑:利用事件冒泡,点击删除按钮时,事件会冒泡到
<tbody>上; - 通过
e.target判断触发事件的元素是否为删除按钮; - 通过
parentElement向上查找,获取当前行<tr>并调用remove()方法移除; - 移除后调用
renderRowStyle()重新校准样式。
- 核心逻辑:利用事件冒泡,点击删除按钮时,事件会冒泡到
隔行变色函数
renderRowStyle()javascript
运行
function renderRowStyle() { const trList = document.querySelectorAll('tbody tr'); for (let i = 0; i < trList.length; i++) { trList[i].classList.remove('blue-bg'); if ((i + 1) % 2 === 0) { trList[i].classList.add('blue-bg'); } } }- 遍历所有行,先移除所有行的
.blue-bg类,避免样式残留; - 判断行的索引
i+1是否为偶数,若是则添加.blue-bg类,实现隔行变色; - 每次新增或删除行后都调用该函数,保证样式始终正确。
- 遍历所有行,先移除所有行的
四、功能测试与优化点
1. 功能测试
- 新增行:点击 “新增行” 按钮,表格会新增一行,序号依次为 1、2、3...,数字依次为 200、300、400...,偶数行自动显示蓝色背景;
- 删除行:点击某行的 “删除” 按钮,该行会被移除,剩余行的隔行变色样式会自动重新计算,保持正确;
- 样式稳定性:无论新增多少行、删除任意行,隔行变色的效果始终稳定,不会出现错乱。
2. 优化点
- 序号优化:当前代码中
currentIndex在删除行后不会重置,若需要删除行后序号重新连续,可在renderRowStyle()函数中遍历行并重新设置序号; - 数据持久化:可将表格数据存储在数组中,新增行时向数组添加数据,删除行时从数组移除数据,实现 “数据驱动视图”;
- 空表格提示:当表格没有行时,可在
<tbody>中添加 “暂无数据” 的提示行,提升用户体验。
五、总结与拓展
本文通过原生 JavaScript 实现了动态表格的增删与隔行变色,核心是掌握DOM 动态创建、事件委托和样式重绘这三个知识点。这些知识点是前端开发的基础,也是学习 Vue、React 等框架的前置条件 —— 框架的底层原理正是基于这些原生 API 封装而来。
拓展方向
- 实现表格数据的本地存储(
localStorage),刷新页面后数据不丢失; - 添加行编辑功能,点击单元格可修改内容;
- 实现表格排序功能,点击表头可按序号或数字升序 / 降序排列。