要求:
设计一个可编辑表格,包括:
- 对页面中数据进行修改、保存、删除
- 输入数据后会对数据进行检查,不符合要求时有提示,并强制改正后方可正确输入
- 可以增加新的数据行
- 适当进行扩展(如:esc、enter键盘绑定事件)
主要设计思路:
HTML设计思路
- 表头被定义为一个table元素,包含thead和tbody;thead包含表头行,编号、姓名、邮箱、电话号码、操作,tbody包含表格数据行,用于显示已存在的数据
- 用form元素实现新的数据行的添加,手动输入数据,点击新增按钮之后,新的数据行会被添加到table表格的最后
CSS设计思路
css样式用于定义表格的样式,包括表格的边框、单元格内边距、文本对齐、操作按钮样式、按钮悬浮点击样式等,还需要定义可操作和不可操作时按钮的不同样式
JS设计思路
- 点击操作中的修改、保存、删除按钮,会触发对应按钮事件触发的函数实现
- 完成修改、保存、删除事件函数的具体实现
- 完成手动添加新的数据行的函数实现
- 编写正则表达式并判断输入是否合法
- 绑定esc、enter的键盘监听事件
- 绑定按钮事件
实现方法:
用到的实现方法有,部分举例:
- getElementById( );//获取元素
- querySelectorAll( );//返回文档中匹配指定 CSS 选择器的所有元素
- querySelector()//返回文档中匹配指定 CSS 选择器的指定元素或选择器组匹配的第一个元素
- textContent //返回指定节点的文本内容
- removeAttribute() //删除元素属性
- setAttribute() // 设置元素属性
- createElement() //创建元素节点
- appendChild()//将节点(元素)作为最后一个子元素添加到元素
核心代码展示:
使用html:构建表格基本结构,展示已有数据
<table id="table">
<thead>
<tr>
<th>编号</th>
<th>姓名</th>
<th>邮箱</th>
<th>电话号码</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<!--contenteditable=true表示内容可编辑,以下为原始数据-->
<td contenteditable="true">001</td>
<td contenteditable="true">张三</td>
<td contenteditable="true">zhangsan@example.com</td>
<td contenteditable="true">13811112222</td>
<td>
<button class="edit button">修改</button>
<!-- 未修改时默认保存不可用 -->
<button class="save button" disabled>保存</button>
<button class="delete button">删除</button>
</td>
</tr>
<!--同理,可以设置多行初始数据-->
</tbody>
</table>
<form id="add-form">
<!-- placehol占位符,在输入框中默认显示 -->
<input type="text" id="add-编号" placeholder="编号" required>
<input type="text" id="add-姓名" placeholder="姓名" required>
<input type="email" id="add-邮箱" placeholder="邮箱" required>
<input type="tel" id="add-电话号码" placeholder="电话号码" required>
<button type="submit" class="button">新增</button>
</form>
使用javascript:主要功能实现,使用了多个函数
首先要获取到table以及添加栏,才能进行后续的操作
const table = document.getElementById('table');
const addForm = document.getElementById('add-form');
再定义函数,进行事件绑定等等,此处以保存操作为例:
// 定义函数,点击保存,编辑状态下的保存操作
function saveRow(row) {
const tds = row.querySelectorAll('td');
//textContent属性属性返回指定节点的文本内容
const num = tds[0].textContent;
const name = tds[1].textContent;
const email = tds[2].textContent;
const phone = tds[3].textContent;
//邮箱和电话号码匹配验证
//邮箱正则表达式:\S+匹配一个或多个非空格字符 xxx@xx.xxx
const emailRegex = /^\S+@\S+\.\S+$/;
//电话号码正则表达式:1开头 [3-9]之间任意数字 \d匹配一个数字0-9 {9}匹配\d表达式9次
const phoneRegex = /^1[3-9]\d{9}$/;
//验证
if (!emailRegex.test(email) || !phoneRegex.test(phone)) {
alert('邮箱或电话号码不合法');
return;
}
//移除html表格单元格的可编辑属性的方法(将可编辑状态设置为不可编辑)
//该方法可以在不重新加载页面的情况下实时更新表格单元格的编辑属性,点击保存后不可在直接编辑
tds[0].removeAttribute('contenteditable');
tds[1].removeAttribute('contenteditable');
tds[2].removeAttribute('contenteditable');
tds[3].removeAttribute('contenteditable');
//默认编辑按钮可用,保存按钮不可用
row.querySelector('.edit').disabled = false;
row.querySelector('.save').disabled = true;
}
//定义函数,点击保存,触发保存操作
function handleSaveClick(event) {
//event.target表示被点击的元素 closest()接收一个css选择器做参数
const row = event.target.closest('tr');//找到离当前元素最近的tr元素
saveRow(row); //保存该行信息,调用第一个函数(保存函数)
}
// 绑定事件
//用document.querySelectorAll()方法查询了表格中所有需要添加事件监听的修改按钮
const editBtns = document.querySelectorAll('.edit');
//使用for循环为每个修改按钮添加监听
const saveBtns = document.querySelectorAll('.save');
for (const btn of saveBtns) {
btn.addEventListener('click', handleSaveClick);
}
其中正则表达式的使用,就是为了实现可编辑表格的内容验证功能,验证输入的内容是否符合要求,符合要求之后才能保存成功
修改、删除功能的代码编写思路与保存差不多,都是函数与事件的触发,明白了思路就简单起来了
添加栏的实现要特别一些,因为它是在table下面添加全新的一行,同样要对表单进行验证,核心代码如下:
//定义函数,用于处理添加表单提交事件的函数,向表格中添加新的一行数据
function handleAddFormSubmit(event) {
event.preventDefault();//用于阻止默认的表单提交行为,避免页面刷新重新加载
//使用了document.getElementById()方法获取四个输入框的值
const num = document.getElementById('add-编号').value;
const name = document.getElementById('add-姓名').value;
const email = document.getElementById('add-邮箱').value;
const phone = document.getElementById('add-电话号码').value;
// 邮箱和电话号码匹配验证,同上述保存函数
const emailRegex = /^\S+@\S+\.\S+$/;
const phoneRegex = /^1[3-9]\d{9}$/;
if (!emailRegex.test(email) || !phoneRegex.test(phone)) {
alert('邮箱或电话号码不合法');
return;
}
//使用了document.createElement()方法,创建一个新的表格行元素tr
const newRow = document.createElement('tr');
//innerHTML属性来设置这一行的HTML内容(四个单元格内容,三个按钮)
newRow.innerHTML = `
<td contenteditable="true">${num}</td>
<td contenteditable="true">${name}</td>
<td contenteditable="true">${email}</td>
<td contenteditable="true">${phone}</td>
<td>
<button class="edit button">修改</button>
<button class="save button" disabled>保存</button>
<button class="delete button">删除</button>
</td>
`;
//为三个按钮分别添加监听事件,事件分别由上述定义的handleEditClick()、handleSaveClick()和handleDeleteClick()来处理
newRow.querySelector('.edit').addEventListener('click', handleEditClick);
newRow.querySelector('.save').addEventListener('click', handleSaveClick);
newRow.querySelector('.delete').addEventListener('click', handleDeleteClick);
//使用了appendChild()方法添加新行
table.querySelector('tbody').appendChild(newRow);
addForm.reset(); // 重置添加栏(表单)
}
最后还要为监听栏设置监听
//为添加栏设置监听
addForm.addEventListener('submit', handleAddFormSubmit);
拓展部分对键盘事件进行了绑定,这一部分的绑定很简单,但目前的实现还有一点问题,无法进行表单验证:
//绑定键盘事件监听,enter与esc
document.addEventListener('keydown', function (event) {
if (event.keyCode==13) {
//获取当前正在编辑的元素
const e1 = document.activeElement;
saveRow(row);
e1.blur(); // 令当前编辑元素失焦,从而保存编辑状态
}
if (event.keyCode==27) {
//获取当前正在编辑的元素
const e2 = document.activeElement;
//令当前编辑元素失焦,实现了让当前元素退出编辑状态
e2.blur();
}
});
拓展思考
基于数据的web页面设计与开发思路和方法
在后续的可编辑表格代码改进中,我们使用了JSON,json就可以用于前后端数据的交互,后端的数据在web页面中展示出来,数据与页面是动态绑定的,一方改变另一方也会随之改变,思路与上面大致相当;
首先仍然要写出表头:
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Phone</th>
<th>操作</th>
</tr>
</thead>
再写出json数据:
const jsonData = [
{id: 1, name: '张三', email: 'zhangsan@example.com', phone: '13811112222'},
{id: 2, name: '李四', email: 'lisi@example.com', phone: '13911113333'},
{id: 3, name: '王五', email: 'wangwu@example.com', phone: '13722223333'}
];
获取到当前table的tbody之后,通过循环数据生成表格行,包括document.createElement()方法的使用来创建td等等,部分代码展示:
const row = document.createElement('tr');
const idCell = document.createElement('td');
idCell.textContent = item.id;
row.appendChild(idCell);
此方法实现中,操作仅有删除和修改,验证、新增行暂未实现:
const deleteButton = document.createElement('button');
deleteButton.textContent = '删除';
deleteButton.className = 'delete button';
deleteButton.addEventListener('click', () => {
table.removeChild(row);
});
const operationCell = document.createElement('td');
operationCell.appendChild(deleteButton);
row.appendChild(operationCell);