用 JavaScript 打造交互式表格:添加与删除行功能
前言
在网页开发中,创建交互式表格是很常见的。今天我们通过一个示例,来展示如何使用 HTML、CSS 和 JavaScript 实现一个能够动态添加和删除行的表格,并详细解释其中 JavaScript 部分的代码逻辑。
功能展示
- 初始状态:页面加载后,表格已经存在一行数据,包含序号、内容以及一个删除按钮。
- 添加行:点击 “添加行” 按钮,表格会新增一行,内容列的数据每次按固定值递增。
- 删除行:点击每行中的 “删除” 按钮,对应的行将从表格中移除。
- 序号与颜色更新:每次添加或删除行后,表格的序号会重新排序,并且根据行的奇偶性,为行设置不同的背景颜色,以增强可读性。
效果展示
点击删除按钮会删除对应的数据,并且后续的数据继续替补上一条数据的序号,但内容不变,颜色仍然是偶数行



代码部分
HTML结构
这里定义了一个基本的 HTML 页面结构,包含一个具有特定样式的表格。thead部分定义了表头,tbody部分初始有一行数据,并且页面底部有一个用于添加行的按钮。
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title></title><style type="text/css">#tablee {border-collapse: collapse;text-align: center;}td {border-style: solid;border-width: 1px;padding: 5px;}</style>
</head><body><table id="tablee" cellspacing="" cellpadding=""><thead><tr><td>序号</td><td>内容</td><td>操作</td></tr></thead><tbody><tr><td>1</td><td>100</td><td><button id="deleteButton">删除</button></td></tr></tbody></table><button id="addButton">添加行</button>
CSS部分
#tablee {border-collapse: collapse;text-align: center;
}td {border-style: solid;border-width: 1px;padding: 5px;
}
JS部分
1.变量声明及初始化
addButton:通过getElementById方法获取页面中的 “添加行” 按钮元素,以便后续为其添加点击事件。tbody:使用querySelector获取表格的tbody元素,后续对表格行的添加、删除操作都将围绕这个元素进行。data:初始化一个数据变量,用于生成 “内容” 列的数据,初始值为 100。
// 获取添加行按钮,为了添加事件
let addButton = document.getElementById('addButton');
// 获取tbody,为了进行一系列操作(对他的子集)
let tbody = document.querySelector('tbody');
// 声明数据 这是初始化的数据 从100开始
let data = 100;
2.添加行功能
- 事件绑定:为
addButton添加click事件监听器,当按钮被点击时,执行回调函数。 - 创建新行及单元格:
- 使用
document.createElement('tr')创建一个新的表格行元素newTr。 - 依次创建三个
td单元格,分别用于显示序号(numTd)、内容(contentTd)和操作按钮(operateTd)。
- 使用
- 填充单元格内容:
- 对 “内容” 单元格
contentTd,先将data的值增加 100,然后将新值写入contentTd的innerHTML。 - 为 “操作” 单元格
operateTd创建一个 “删除” 按钮tdButton,并将按钮添加到该单元格。
- 对 “内容” 单元格
- 添加新行到表格:将包含三个单元格的
newTr行添加到tbody中。 - 更新序号和颜色:调用
setNumberAndColor函数,对表格的序号和行背景颜色进行更新。
// 给添加按键添加事件
addButton.onclick = function () {// 1.创建一个新的tr行let newTr = document.createElement('tr');// 2.创建第一个单元格let numTd = document.createElement('td');// 2.1.把第一个td插到Tr里newTr.appendChild(numTd)// 3.创建第二个单元格let contentTd = document.createElement('td');// 3.1.data值加100后,重新赋值给datadata += 100;// 3.2.往contentTd中写入data数据contentTd.innerHTML = data;// 3.3.把contentTd插入到newTrnewTr.appendChild(contentTd);// 4.创建第三个单元格 // 并且第三个单元格里只存放按钮let operateTd = document.createElement('td');// 5.创建删除按钮let tdButton = document.createElement('button');// 5.1 按钮名字改成删除tdButton.innerHTML = '删除'// 5.2把删除按钮插回创建的第三个单元格operateTd.appendChild(tdButton);// 5.3把第三个单元格插到tr行里newTr.appendChild(operateTd);// 5.4最后把newTr行插入到tbody中tbody.appendChild(newTr);// 调用一下封装好的函数 (序号和颜色)setNumberAndColor();
};
3.颜色及序号
- 获取所有行:使用
document.querySelectorAll('tr')获取页面中所有的tr元素,存储在allTr数组中。 - 遍历并设置样式和序号:
- 从索引 1 开始遍历
allTr数组(跳过表头行)。 - 根据索引
i的奇偶性,为每行设置不同的背景颜色。如果i能被 2 整除,背景颜色设为黄色;否则设为白色。 - 通过
querySelector('td:first-child')获取每行的第一个td单元格,将其内容设置为当前的行索引i,从而实现序号的更新。
- 从索引 1 开始遍历
function setNumberAndColor() {// let setNumber = 1;let allTr = document.querySelectorAll('tr'); /*获取所有tr标签 */// 遍历获取到的所有tr// 从下标1开始,并且小于 < 获取到的所有tr的长度for (let i = 1; i < allTr.length; i++) {// 判断是否为偶数if (i % 2 == 0) {// 满足被2整除的 就加一个背景颜色allTr[i].style.backgroundColor = 'yellow';} else {// 否则 就是白色allTr[i].style.backgroundColor = 'white';}// 获取当前tr行 里的第一个td格:用于显示序列号的单元格let getShowNumber = allTr[i].querySelector('td:first-child');if (getShowNumber) {// ↑↑满足条件的话, ↓↓就把序号添加到 获取的tr行里getShowNumber.innerHTML = i; // 设置序号// 序号增加1,往后递增// setNumber++; // 序号递增}}
}
4.删除行功能
- 事件委托:在
tbody元素上添加click事件监听器。这样当点击tbody内的任何元素时,都会触发该事件。 - 判断点击目标:获取事件的目标元素
targetElement,检查其innerHTML是否为 “删除”。如果是,则表示点击了 “删除” 按钮。 - 删除对应行:通过
parentElement两次获取到按钮所在的tr行元素,然后使用tbody.removeChild(tr)将该行从tbody中移除。 - 更新序号和颜色:调用
setNumberAndColor函数,确保删除行后表格的序号和背景颜色依然保持正确的显示。
// 删除按钮
// 用的是 事件监听,因为要确定我在页面上 点的是哪一个元素
tbody.addEventListener('click', function (e) {let targetElement = e.targetif (targetElement.innerHTML == '删除') {// 获取到当前元素的父级的父级(他爷爷)let tr = targetElement.parentElement.parentElement;// 从tbody中删除对应的trtbody.removeChild(tr);// 调用封装的函数(序号颜色) // 这里调用是因为防止删除白色行时,下面的黄色行自动向上顶,导致邻近的两行都是黄色setNumberAndColor();}
})
各行换色思路二:利用字符串拼接
(大致思路一致,不过多赘述)
代码展示
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title></title><style type="text/css">#tablee {border-collapse: collapse;text-align: center;}td {border-style: solid;border-width: 1px;padding: 5px;}</style></head><body><table id="tablee" cellspacing="" cellpadding=""><thead><tr><td>序号</td><td>内容</td><td>操作</td></tr></thead><tbody></tbody></table><!-- 这个思路类似于:一个城市模块化积木,每个区域有需要新添/放置设施(添加行tr)把积木在一个底座上一个一个拼起来 然后塞到相应的区域(底座:空字符串;积木:被拼接的td;区域:tbody)因为城市的区域很大 不可能每个地方都重新造设施(改变/添加新的数据) 所以用同一个拼好的积木模板(封装好的函数) 往区域里放置(调用函数)但是有时候想对区域里某个地方的模板进行修改时 就需要把新添的内容放到模板上(添加数据后,数据发生改变就重新调用渲染函数往里面传参数)--><button id="addButton" type="button">添加行</button><script type="text/javascript">/* 声明一个数组(开始显示的数据) */let data = [100];/* 内容格里的值 */let content = 100;/* 初始化每次点击,添加按钮的初始值 */let addNumber=100;/* 封装渲染函数 */function xuanran(data) {/* 拼接字符串,为了拼接tr行的字符串 */let str = '';/* 循环data,循环几次 就拼接几次 */for (let i = 1; i < data.length; i++) {/* 拼接字符串,将后续拼接的内容添加到str里 *//* 用三元去加颜色 */str += '<tr style=" background-color:' + (i % 2 == 0 ? 'pink' : '') + ';">' +/* 1.拼接第一个单元格(序号) */'<td>' + i + '</td>' +/* 2.拼接第二个单元格(内容,内容上面已经给了 从100开始) */'<td>' + data[i] + '</td>' +/* 3.拼接第三个单元格(删除按钮)并设置了自定义属性data_index并给了一个i的值为下标,用来确定按钮对应的是哪一行*/'<td><button data_index="' + i + '">删除</button></td>' +'</tr>'}/* 上面拼接完之后 并不在页面上需要往tbody里塞*/let getBody = document.querySelector('tbody');/* 把拼接好的字符串写入tbody里 */getBody.innerHTML = str;};/* 把conten放入data里 */data.push(content);/* 每次添加一行content都+100 */content += 100;/* 上面一行数据发生变化了,所以调用渲染函数(传一下新的参) */xuanran(data);// 删除按钮的事件监听 /* 1.先获取一下tbody */let tbody = document.querySelector('tbody');/* 2.然后对tbody监听。添加click点击事件监听。e是一个事件对象包含了 与该点击事件相关的各种信息 */tbody.addEventListener('click', function(e) {/* 3.判断点击的是否为删除 e.target 是事件对象 e 的一个属性 ,它指向谁被点击了通过e.target.innerHTML去获取被点击的文本内容是否满足条件*/if (e.target.innerHTML == '删除') {/* 4.获取要删除数据的索引 *//* getAttribute 是 DOM 元素的一个方法,用于获取指定元素的某个属性的值 *//* 通过e.target来确定谁被点了 然后获取它的下标 */let getIndex = e.target.getAttribut e('data_index');/* 5.从数组中删除对应的元素 *//* 删除获取的getIndex,删除1个元素(,逗号前是已经获取到的元素的对应下标,后是要删除的元素个数) */data.splice(getIndex, 1);/* 因为值变化了 所以重新调用渲染一下,把新参数传进去 */xuanran(data);}});// 添加行按钮 /* 1.先获取添加按钮 */let addDeleteButto = document.getElementById('addButton');/* 2.给添加按钮上点击事件监听 */addDeleteButto.addEventListener('click', function() {/* 每点击一次添加 内容数值都加100,最上面写了初始值 */addNumber += 100;/* 把每次叠加的值插入到data里 */data.push(addNumber);/* 因为数变化了 ,所以重新渲染传参 */xuanran(data); });</script></body>
</html>
区别部分
- 对于数组中的每一项,拼接一个完整的
<tr>元素字符串。- 背景颜色设置:使用三元运算符
(i % 2 == 0 ? 'pink' : '')根据当前行的索引i的奇偶性来设置背景颜色。如果i是偶数,背景颜色为pink;否则不设置背景颜色。 - 序号单元格:第一个
<td>元素显示当前行的序号i。 - 内容单元格:第二个
<td>元素显示data[i]的值,即当前数组项的数据。 - 删除按钮单元格:第三个
<td>元素包含一个<button>元素,按钮上设置了自定义属性data_index,其值为当前行的索引i,用于后续识别要删除的行。
- 背景颜色设置:使用三元运算符
/* 封装渲染函数 */function xuanran(data) {/* 拼接字符串,为了拼接tr行的字符串 */let str = '';/* 循环data,循环几次 就拼接几次 */for (let i = 1; i < data.length; i++) {/* 拼接字符串,将后续拼接的内容添加到str里 *//* 用三元去加颜色 */str += '<tr style=" background-color:' + (i % 2 == 0 ? 'pink' : '') + ';">' +/* 1.拼接第一个单元格(序号) */'<td>' + i + '</td>' +/* 2.拼接第二个单元格(内容,内容上面已经给了 从100开始) */'<td>' + data[i] + '</td>' +/* 3.拼接第三个单元格(删除按钮)并设置了自定义属性data_index并给了一个i的值为下标,用来确定按钮对应的是哪一行*/'<td><button data_index="' + i + '">删除</button></td>' +'</tr>'}/* 上面拼接完之后 并不在页面上需要往tbody里塞*/let getBody = document.querySelector('tbody');/* 把拼接好的字符串写入tbody里 */getBody.innerHTML = str;};
相关文章:
用 JavaScript 打造交互式表格:添加与删除行功能
前言 在网页开发中,创建交互式表格是很常见的。今天我们通过一个示例,来展示如何使用 HTML、CSS 和 JavaScript 实现一个能够动态添加和删除行的表格,并详细解释其中 JavaScript 部分的代码逻辑。 功能展示 初始状态:页面加载后…...
Linux02——Linux的基本命令
目录 ls 常用选项及功能 综合示例 注意事项 cd和pwd命令 cd命令 pwd命令 相对路径、绝对路径和特殊路径符 特殊路径符号 mkdir命令 1. 功能与基本用法 2. 示例 3. 语法与参数 4. -p选项 touch-cat-more命令 1. touch命令 2. cat命令 3. more命令 cp-mv-rm命…...
服务器虚拟化实战:架构、技术与最佳实践
📝个人主页🌹:一ge科研小菜鸡-CSDN博客 🌹🌹期待您的关注 🌹🌹 1. 引言 服务器虚拟化是现代 IT 基础设施的重要组成部分,通过虚拟化技术可以提高服务器资源利用率、降低硬件成本&am…...
.Net WebAPI -[HttpPut(“{fileServiceId:int}“)]
[HttpPut("{fileServiceId:int}")] 这个写法是 ASP.NET Core 中的一个路由特性,用于定义一个 HTTP PUT 请求的路由,并指定路由参数的类型。 解析 HttpPut [HttpPut]: 这是一个 ASP.NET Core 的路由特性,用于标记一个方…...
AI大模型开发原理篇-1:语言模型雏形之N-Gram模型
N-Gram模型概念 N-Gram模型是一种基于统计的语言模型,用于预测文本中某个词语的出现概率。它通过分析一个词语序列中前面N-1个词的出现频率来预测下一个词的出现。具体来说,N-Gram模型通过将文本切分为长度为N的词序列来进行建模。 注意:这…...
[250201] isd v0.3.0 发布:全新快捷键逻辑及其他改进 | Puma 6.6.0 版本发布
目录 isd v0.3.0 发布:全新快捷键逻辑及其他改进Puma 6.6.0 版本发布🆕 新特性🛠️Bug 修复💪 性能改进🔄 代码重构 isd v0.3.0 发布:全新快捷键逻辑及其他改进 isd (Interactive Systemd) 是一款文本用户…...
修改题注标签
为了防止原博主删帖,故转到自己账号中,出处如下 转载:(152条消息) 修改题注标签_Z_shsf的博客-CSDN博客_seq图arabic怎么解决 问题:论文中存在 标签图1- 和标签图 ,如何合并两种标签 成为图 并一起计数 按 AltF9 查…...
pytorch实现循环神经网络
人工智能例子汇总:AI常见的算法和例子-CSDN博客 PyTorch 提供三种主要的 RNN 变体: nn.RNN:最基本的循环神经网络,适用于短时依赖任务。nn.LSTM:长短时记忆网络,适用于长序列数据,能有效解决…...
Python从零构建macOS状态栏应用(仿ollama)并集成AI同款流式聊天 API 服务(含打包为独立应用)
在本教程中,我们将一步步构建一个 macOS 状态栏应用程序,并集成一个 Flask 服务器,提供流式响应的 API 服务。 如果你手中正好持有一台 MacBook Pro,又怀揣着搭建 AI 聊天服务的想法,却不知从何处迈出第一步,那么这篇文章绝对是你的及时雨。 最终,我们将实现以下功能: …...
leetcode 2080. 区间内查询数字的频率
题目如下 数据范围 示例 这题十分有意思一开始我想对每个子数组排序二分结果超时了。 转换思路:我们可以提前把每个数字出现的位置先记录下来形成集合, 然后拿着left和right利用二分查找看看left和right是不是在集合里然后做一个相减就出答案了。通过…...
深入了解 SSRF 漏洞:原理、条件、危害
目录 前言 SSRF 原理 漏洞产生原因 产生条件 使用协议 使用函数 漏洞影响 防御措施 结语 前言 本文将深入剖析 SSRF(服务端请求伪造)漏洞,从原理、产生原因、条件、影响,到防御措施,为你全面梳理相关知识&am…...
11.QT控件:输入类控件
1. Line Edit(单行输入框) QLineEdit表示单行输入框,用来输入一段文本,但是不能换行。 核心属性: 核心信号: 2. Text Edit(多行输入框) QTextEdit表示多行输入框,也是一个富文本 & markdown编辑器。并且能在内容超…...
Cesium+Vue3教程(011):打造数字城市
文章目录 Cesium打造数字城市创建项目加载地球设置底图设置摄像头查看具体位置和方向添加纽约建筑模型并设置样式添加纽约建筑模型设置样式划分城市区域并着色地图标记显示与实现实现飞机巡城完整项目下载Cesium打造数字城市 创建项目 使用vite创建vue3项目: pnpm create v…...
Windows系统本地部署deepseek 更改目录
本地部署deepseek 无论是mac还是windows系统本地部署deepseek或者其他模型的命令和步骤是一样的。 可以看: 本地部署deepsek 无论是ollama还是部署LLM时候都默认是系统磁盘,对于Windows系统,我们一般不把应用放到系统盘(C:)而是…...
基于Python的药物相互作用预测模型AI构建与优化(下.代码部分)
四、特征工程 4.1 分子描述符计算 分子描述符作为量化分子性质的关键数值,能够从多维度反映药物分子的结构和化学特征,在药物相互作用预测中起着举足轻重的作用。RDKit 库凭借其强大的功能,为我们提供了丰富的分子描述符计算方法,涵盖了多个重要方面的分子性质。 分子量…...
[Python学习日记-79] socket 开发中的粘包现象(解决模拟 SSH 远程执行命令代码中的粘包问题)
[Python学习日记-79] socket 开发中的粘包现象(解决模拟 SSH 远程执行命令代码中的粘包问题) 简介 粘包问题底层原理分析 粘包问题的解决 简介 在Python学习日记-78我们留下了两个问题,一个是服务器端 send() 中使用加号的问题,…...
origin如何在已经画好的图上修改数据且不改变原图像的画风和格式
例如我现在的.opju文件长这样 现在我换了数据集,我想修改这两个图表里对应的算法里的数据,但是我还想保留这图像现在的形式,可以尝试像下面这样做: 右击第一个图,出现下面,选择Book[sheet1] 选择工作簿 出…...
OPENGLPG第九版学习
文章目录 一、OpenGL概述二、着色器基础三、OpenGL绘制方式四、颜色、像素和片元五、视口变换、裁减、剪切与反馈六、纹理与帧缓存七、光照与阴影八、程序式纹理 skip九、细分着色器 skip十、几何着色器 skip十一、内存十二、计算着色器 skip附录 A 第三方支持库附录 B OpenGL …...
5.3.2 软件设计原则
文章目录 抽象模块化信息隐蔽与独立性衡量 软件设计原则:抽象、模块化、信息隐蔽。 抽象 抽象是抽出事物本质的共同特性。过程抽象是指将一个明确定义功能的操作当作单个实体看待。数据抽象是对数据的类型、操作、取值范围进行定义,然后通过这些操作对数…...
【ArcGIS遇上Python】批量提取多波段影像至单个波段
本案例基于ArcGIS python,将landsat影像的7个波段影像数据,批量提取至单个波段。 相关阅读:【ArcGIS微课1000例】0141:提取多波段影像中的单个波段 文章目录 一、数据准备二、效果比对二、python批处理1. 编写python代码2. 运行代码一、数据准备 实验数据及完整的python位…...
Spring Security(maven项目) 3.0.2.9版本 --- 改
前言: 通过实践而发现真理,又通过实践而证实真理和发展真理。从感性认识而能动地发展到理性认识,又从理性认识而能动地指导革命实践,改造主观世界和客观世界。实践、认识、再实践、再认识,这种形式,循环往…...
仿真设计|基于51单片机的温度与烟雾报警系统
目录 具体实现功能 设计介绍 51单片机简介 资料内容 仿真实现(protues8.7) 程序(Keil5) 全部内容 资料获取 具体实现功能 (1)LCD1602实时监测及显示温度值和烟雾浓度值; (2…...
深入剖析 CSRF 漏洞:原理、危害案例与防护
目录 前言 漏洞介绍 漏洞原理 产生条件 产生的危害 靶场练习 post 请求csrf案例 防御措施 验证请求来源 设置 SameSite 属性 双重提交 Cookie 结语 前言 在网络安全领域,各类漏洞层出不穷,时刻威胁着用户的隐私与数据安全。跨站请求伪造&…...
rust跨平台调用动态库
动态库在不同的操作系统,扩展名是不一样的,所以要做处理: static LIB: Lazy<Mutex<Option<Library>>> Lazy::new(|| Mutex::new(None));type CreateFunc unsafe extern "C" fn(*const c_char, *const c_char) -> c_int…...
buuuctf_秘密文件
题目: 应该是分析流量包了,用wireshark打开 我追踪http流未果,分析下ftp流 追踪流看看 用户 “ctf” 使用密码 “ctf” 登录。 PORT命令用于为后续操作设置数据连接。 LIST命令用于列出 FTP 服务器上目录的内容,但在此日志中未…...
课程设计|结构力学
课 程 设 计 第一部分 (结构力学) 2、两种结构在静力等效荷载作用下,内力有哪些不同?(分析比较) 1/2 1 1 1 1 1 1/2 1/4 11(1/2) 1/4 图1求解过程及结果: 轴力图: 内力计算 单位&…...
三次方根pow
给定一个浮点数n,求它的三次方根。 输入格式: 共一行,包含一个浮点数n,−10000≤n≤10000。 输出格式: 共一行,包含一个浮点数,表示问题的解。 注意,结果保留6位小数。 输入样例: 1000.00输出样例: 10.000000 …...
跟李沐学AI:视频生成类论文精读(Movie Gen、HunyuanVideo)
Movie Gen:A Cast of Media Foundation Models 简介 Movie Gen是Meta公司提出的一系列内容生成模型,包含了 3.2.1 预训练数据 Movie Gen采用大约 100M 的视频-文本对和 1B 的图片-文本对进行预训练。 图片-文本对的预训练流程与Meta提出的 Emu: Enh…...
【项目集成Husky】
项目集成Husky 安装初始化 Husky在.husky → pre-commit文件中添加想要执行的命令 安装 使用 Husky 可以帮助你在 Git 钩子中运行脚本,例如在提交代码前运行测试或格式化代码pnpm add --save-dev husky初始化 Husky npx husky init这会在项目根目录下创建一个 .hu…...
keil5如何添加.h 和.c文件,以及如何添加文件夹
1.简介 在hal库的编程中我们一般会生成如下的几个文件夹,在这几个文件夹内存储着各种外设所需要的函数接口.h文件,和实现函数具体功能的.c文件,但是有时我们想要创建自己的文件夹并在这些文件夹下面创造.h .c文件来实现某些功能,…...
