用 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后,重新赋值给data
data += 100;
// 3.2.往contentTd中写入data数据
contentTd.innerHTML = data;
// 3.3.把contentTd插入到newTr
newTr.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.target
if (targetElement.innerHTML == '删除') {
// 获取到当前元素的父级的父级(他爷爷)
let tr = targetElement.parentElement.parentElement;
// 从tbody中删除对应的tr
tbody.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;
};