我们使用数据驱动的方式来实现一个简单的学生管理系统。如图:
管理系统功能介绍:
- 刷新页面后列表中新增的学生数据不会丢失。
- 删除操作有二次弹框确认,确认后删除当前行的学生信息。
- 表单字段有非空校验和格式校验,校验不通过不允许添加。
- 点击添加按钮会往列表中添加新增的学生信息,同时表单数据清空。
- 点击重置按钮清空表单中所填写的学生信息。
- 点击编辑按钮,可在当前行内编辑学生信息,编辑按钮变为确定按钮,点击确认按钮会修改该学生数据。
数据驱动
学生管理系统是以数据驱动的形式进行编辑,所以我们先了解一下什么是数据驱动。
数据驱动是一种开发模式,它侧重于使用数据来推动应用逻辑和用户界面(UI)的变化。在传统的开发模式中,开发者需要手动操作DOM来改变页面上的元素。这种方式会随着页面复杂性的增加而变得难以维护,并且可能导致性能问题,而数据驱动就可以解决这一问题。
项目实现
样式代码:
.red {
font-size: 12px;
color: red;
}
.none {
display: none;
}
.inline {
display: '';
}
HTML代码:
<h1>学生管理系统</h1>
<label for=""><span>*</span>用户名:<input type="text" id="userName"></label>
<br />
<span class="valid-user red none">请输入正确的用户名</span>
<br />
<label for=""><span>*</span>密码:<input type="text" id="userPassword"></label>
<br />
<span class="valid-pwd red none">请输入正确的密码</span>
<br />
<label for=""><span>*</span>邮箱:<input type="text" id="userEmail"></label>
<br />
<span class="valid-email red none">请输入正确的邮箱</span>
<br />
<button id="add">添加</button>
<button id="reset">重置</button>
<table border="1">
<thead>
<tr>
<td>编号</td>
<td>姓名</td>
<td>密码</td>
<td>邮箱</td>
<td>操作</td>
</tr>
</thead>
<tbody id="container">
</tbody>
</table>
JS代码:
第一步:可以先封装一个获取DOM对象的工具方法
function $$(selector, all = false) {
if(typeof selector !== 'string') return
return all ? document.querySelectorAll(selector) : document.querySelector(selector)
}
第二步:写表格数据渲染实现数据驱动
let list = handleGetStorage('list').length ? handleGetStorage('list') : [
{ id: 1, name: '张三1', password: '666', email: '11@qq.com', isEdit: false },
{ id: 2, name: '张三2', password: '666', email: '11@qq.com', isEdit: false },
{ id: 3, name: '张三3', password: '666', email: '11@qq.com', isEdit: false },
]
第三步:渲染视图,由于后期还要再使用,所以直接把它封装成一个方法,方便调用
function render() {
$$('#container').innerHTML = list.map((item, index) => {
return `
<tr>
<td>${item.id}</td>
<td>
<input class="user-name-input" style="display: ${item.isEdit ? '' : 'none'};" value="${item.name}" />
<span style="display: ${item.isEdit ? 'none' : ''};">${item.name}</span>
</td>
<td>${item.password}</td>
<td>${item.email}</td>
<td>
<button style="background: ${item.isEdit ? 'green' : 'blue'};" class="edit" data-id="${item.id}" data-type="${item.isEdit ? 'ok' : 'edit'}" data-index="${index}">${item.isEdit ? '完成' : '编辑'}</button>
<button class="del" data-id="${item.id}">删除</button>
</td>
</tr>`
}).join('')
handleDeleteStudent() // 删除学生数据
handleEditStudent() // 编辑学生数据
handleSetStorage('list', list) // 注意:删除操作执行完后再执行本地存储操作
}
render()
第四步:实现删除功能
function handleDeleteStudent() {
$$('.del', true).forEach(el => {
el.addEventListener('click', function () {
if (confirm('此操作将永久删除该文件,是否继续?')) {
list = list.filter(v => v.id !== +this.dataset.id)
// 渲染视图
render()
}
})
})
}
第五步:实现表单重置按钮功能
const userName = $$('#userName')
const userPassword = $$('#userPassword')
const userEmail = $$('#userEmail')
const emailRegExp = /^[\w-]+(\.[\w-]+)*@([a-zA-Z0-9-]+\.)+(com|org|net|edu|gov|co|io|info|biz|me|us)$/
function handleClear() {
userName.value = ''
userPassword.value = ''
userEmail.value = ''
}
$$('#reset').onclick = function () {
handleClear()
}
第六步:实现表单添加功能,和表单校验功能
$$('#add').onclick = function () {
const validUser = $$('.valid-user')
const valiePwd = $$('.valid-pwd')
const validEmail = $$('.valid-email')
let flag = true // 因为要根据多个字段的校验结果控制return,所以给一个全局开关,默认为true通过
// 实现表单校验功能
if (!userName.value) { // 用户名校验不通过,直接退出
validUser.classList.remove('none')
validUser.classList.add('inline')
flag = false
} else {
validUser.classList.add('none')
validUser.classList.remove('inline')
}
if (!userPassword.value) { // 密码校验不通过,直接退出
valiePwd.classList.remove('none')
valiePwd.classList.add('inline')
flag = false
} else {
valiePwd.classList.add('none')
valiePwd.classList.remove('inline')
}
if (!userEmail.value || !emailRegExp.test(userEmail.value)) { // 邮箱校验不通过,直接退出
validEmail.classList.remove('none')
validEmail.classList.add('inline')
flag = false
} else {
validEmail.classList.add('none')
validEmail.classList.remove('inline')
}
if (!flag) { // 如果校验不通过就不执行后面代码
return false // 提前退出
}
list = [...list, {
id: list.length + 1,
name: userName.value,
password: userPassword.value,
email: userEmail.value,
}]
handleClear() // 清空表单数据
render() // 重新渲染视图/通知视图重新渲染
}
第七步:实现编辑功能
function handleEditStudent() {
$$('.edit', true).forEach(el => {
el.addEventListener('click', function () {
const id = this.dataset.id
const type = this.dataset.type
const index = this.dataset.index
list.forEach(item => {
if(+id === item.id) { // 找到点击编辑按钮的当前行数据了
item.isEdit = type !== 'ok'
type === 'ok' && (item.name = $$('.user-name-input', true)[index].value)
}
})
// 渲染视图
render()
})
})
}
}
第八步:实现本地存储功能
function handleSetStorage(key, value) {
window.localStorage.setItem(key, JSON.stringify(value))
}
function handleGetStorage(key) {
r eturn JSON.parse(window.localStorage.getItem(key)) || []
}
// html5的本地存储里只能存字符串,所以如果存储的数据是引用数据要先转化为字符串再存进去
const utils = {
get(key) {
return window.localStorage.getItem(key)
},
set(key, value) {
window.localStorage.setItem(key, value)
},
remove(key) {
window.localStorage.removeItem(key)
},
clear() {
window.localStorage.clear()
}