什么是数据驱动?
数据驱动视图是指通过数据来驱动页面的显示和行为,使得页面的展示和交互元素可以根据数据的变化而自动更新。这种开发模式通常使用前端框架或库来实现,例如Vue.js、React等。简单来说,其实就是通过操作原始数据来进行显示更新页面,通过更改原始数据重新渲染页面。而并非使用dom操作。
数据驱动应用场景
数据驱动应用场景非常广泛,比如,在管理系统、电子商务平台、社交网络等复杂应用中,页面上的数据和用户交互元素需要频繁地更新和响应,数据驱动视图的开发模式能够极大地提高开发效率,并且使得页面的维护和拓展更加容易。
数据驱动案例(学生管理系统)
下面,我们来通过学生管理系统深入了解一下数据驱动,这个项目涉及到了增删改的操作,全部用的是数据驱动。
页面总体效果
页面结构:
页面的布局的和结构
<div class="box">
<h1>学生管理系统</h1>
<div class="ck">
<div class="ck1">
用户名:<input type="text" class="ok2 ok3"><br>
<div class="dk1 none">请输入正确的用户名</div>
</div>
<div class="ck2">
密码:<input type="text" class="ok2 ok4"><br>
<div class="dk2 none">请输入正确的密码</div>
</div>
<div class="ck3">
邮箱:<input type="text" class="ok2 ok5">
<div class="dk3 none">请输入正确的邮箱
</div>
</div>
<div class="ccc">
<button class="btn btn1">添加</button>
<button class="btn btn2">重置</button>
</div>
</div>
<table>
<thead>
<tr>
<td class="text-c">编号</td>
<td>姓名</td>
<td>密码</td>
<td>邮箱</td>
<td>操作</td>
</tr>
</thead>
<tbody id="ttt">
</tbody>
</table>
</div>
页面样式:
通过CSS对页面样式进行设计和美化
* {
margin: 0;
padding: 0;
}
*::selection {
background-color: none;
}
h1 {
text-align: center;
}
.ck {
text-align: center;
margin-top: 20px;
}
.ck1 input {
width: 200px;
height: 23px;
margin-left: 5px;
padding-left: 10px;
outline: none;
border: none;
border: 1px solid #ccc;
}
.ck2 input {
width: 200px;
height: 23px;
margin-left: 24px;
padding-left: 10px;
outline: none;
border: none;
border: 1px solid #ccc;
}
.ck3 input {
width: 200px;
height: 23px;
margin-left: 24px;
padding-left: 10px;
outline: none;
border: none;
border: 1px solid #ccc;
}
.ck1::after {
content: "*";
width: 20px;
height: 20px;
display: block;
position: absolute;
left: 42%;
color: red;
top: 0px;
}
.ck1 {
box-sizing: border-box;
position: relative;
}
.ck2 {
box-sizing: border-box;
position: relative;
}
.ck3 {
box-sizing: border-box;
position: relative;
}
.ck2::after {
content: "*";
width: 20px;
height: 20px;
display: block;
position: absolute;
left: 42%;
color: red;
top: 0px;
}
.ck3::after {
content: "*";
width: 20px;
height: 20px;
display: block;
position: absolute;
left: 42%;
color: red;
top: 0px;
}
.ccc {
margin-top: 20px;
margin-left: 9px;
}
.ok1 {
height: 21px;
margin-left: 22px;
}
.btn {
width: 78px;
color: #fff;
height: 33px;
border: none;
}
.btn1 {
background-color: lawngreen;
}
.btn2 {
background-color: skyblue;
}
table {
margin: 0 auto;
margin-top: 70px;
}
td {
width: 132px;
height: 30px;
}
.text-c {
text-align: center;
}
table .wt {
width: 66px;
}
.an {
width: 51px;
height: 29px;
border: none;
color: #fff;
}
.an1 {
background-color: skyblue;
}
.an2 {
background-color: #ff3040;
}
.none {
display: none;
}
.block {
display: '';
color: #ff3040;
}
数据渲染:
这个部分用于直接渲染页面的基本结构,基于数据驱动的思想,这里是直接封装了一个函数
function render() {
$$('#ttt', true).innerHTML = list.map((item, index) => {
return `
<tr>
<td class="text-c">${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>
<input class="user-name-input1" style="display: ${item.isEdit ? '' : 'none'};" value="${item.password}" />
<span style="display: ${item.isEdit ? 'none' : ''};">${item.password}</span>
</td>
<td>
<input class="user-name-input2" style="display: ${item.isEdit ? '' : 'none'};" value="${item.email}" />
<span style="display: ${item.isEdit ? 'none' : ''};">${item.email}</span>
</td>
<td>
<button class="an an1" 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="an an2" data-id='${item.id}'>删除</button>
</td>
</tr>
`
}).join('')//用于处理转换的问题
}
render()
删除部分:
这里是封装了一个函数的用于调用方便我们去调用,去实时的实现删除功能
function deletestudentInformation() {//删除的函数
$$('.an2', false).forEach(e => {
e.addEventListener('click', function () {
// 给每个元素添加点击事件监听器,当元素被点击时执行以下操作
if (confirm('是否永久删除该条数据,是或否')) {
//判断用户点击时,为true的话进入判断,如果为false的话不进入判断
list = list.filter(v => v.id !== +this.dataset.id)
// 使用数组的 filter 方法过滤出 id 不等于当前元素的 dataset 中的 id 属性值的元素,并重新赋值给 list 变量
render()
}
})
})
}
删除部分优化:
这里的思想就是给document绑定监听事件,所以这里就可以不用封装成函数从而来调用,这样也可以省去我们一部分的空间
// 优化后的代码
document.addEventListener('click', function (e) { //这里给document绑定了一个监听事件,方便去监听事件委托的一个节点
if (e.target.matches('.an2')) {//在JavaScript中,可以使用Element.matches方法(也称为Element.matchesSelector)来判断一个元素是否与指定的选择器匹配
const confirmDelete = confirm('是否永久删除该条数据,是或否');
//判断用户点击时,为true的话进入判断,如果为false的话不进入判断
if (confirmDelete) {
const clickedElementId = parseInt(e.target.dataset.id);
list = list.filter(item => item.id !== clickedElementId);
// 使用数组的 filter 方法过滤出 id 不等于当前元素的 dataset 中的 id 属性值的元素,并重新赋值给 list 变量
render();
}
}
});
重置按钮:
这里的实现思路的话,是用户输入文本框的文本删的麻烦,可以点击重置按钮,可以一键清空用户输入的文字
/ 4、重置
let ok3 = $$('.ok3', true)//这里获取了三个input框的节点
let ok4 = $$('.ok4', true)
let ok5 = $$('.ok5', true)
let RegExp = /[\u4E00-\u9FA5]/ //这里是做的是三个文本框的正则表达式
let RegExp1 = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/
let RegExp2 = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
function resetting() {//这里做了清空操作
ok3.value = ''
ok4.value = ''
ok5.value = ''
}
$$('.btn2', true).onclick = function () {//重置按钮的点击事件
resetting()//这里做了调用函数的操作
}
添加部分:
这里实现用户输入的数据可以添加在页面上,以及给该文本框实现一个正则验证,下面是实现思路
// 5、添加
$$('.btn1', true).onclick = function () {
const dk1 = $$('.dk1', true)
const dk2 = $$('.dk2', true)
const dk3 = $$('.dk3', true)
flag = true
if (!ok3.value || !RegExp.test(ok3.value)) {//这里是做了一个用户名的正则验证
dk1.classList.remove('none')
dk1.classList.add('block')
flag = false
} else {
dk1.classList.remove('block')
dk1.classList.add('none')
}
if (!ok4.value || !RegExp1.test(ok4.value)) {//这里是做了一个密码正则的验证
dk2.classList.remove('none')
dk2.classList.add('block')
flag = false
} else {
dk2.classList.remove('block')
dk2.classList.add('none')
}
if (!ok5.value || !RegExp2.test(ok5.value)) {//这里是做了一个邮箱正则的验证
dk3.classList.remove('none')
dk3.classList.add('block')
flag = false
} else {
dk3.classList.remove('block')
dk3.classList.add('none')
}
if (!flag) {
return false//这里校验不通过的话,就直接退出
}
list = [...list, {
id: list.length + 1,
name: ok3.value,
password: ok4.value,
email: ok4.value,
}]
resetting()
render()
}
本地存储:
实现刷新不会使用户输入的数据丢失,所以这块我们就用到了本地存储
function handleSetStorage(key, value) {
window.localStorage.setItem(key, JSON.stringify(value))//这里是设置了本地存储
}
function handleGetStorage(key) {
return JSON.parse(window.localStorage.getItem(key)) || []//这里是拿取了本地存储
}
编辑功能:
我们为了实现用户想改输入的数据时,设置了修改的按钮,这样可以提升用户的体验
function edit() {//编辑按钮的函数
$$('.an1', false).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', false)[index].value)//这里
type === 'ok' && (item.password = $$('.user-name-input1', false)[index].value)
type === 'ok' && (item.email = $$('.user-name-input2', false)[index].value)
}
})
render()//这里调用渲染函数从新渲染视图
})
})
}
总结与感悟:
通过这个项目,我获得了许多宝贵的经验与知识,我对数据驱动的思想有了更深刻的理解.,我掌握了实现响应式页面更新的技巧,当数据发生变化时,数据能够自动更新,提升了用户体验。并且我了解了本地存储技术,通过它实现了数据永久存储,避免了因页面刷新而导致数据丢失的问题,增强用户体验。这些收获让我更专注于业务逻辑处理,避免使用dom操作,提高开发效率。
我获得了宝贵的经验和知识。我学会了如何构建清晰的前端架构,将业务逻辑与界面表现分离,使得前端代码更易于组织和维护。我掌握了实现响应式页面更新的技巧,当数据发生变化时,页面元素能够自动更新,极大地提升了用户体验。我深入了解了本地存储技术,通过它实现了数据的持久化存储,避免了因页面刷新而导致数据丢失的问题,从而增强了用户体验。在采用数据驱动视图的开发模式中,我们通过单元测试与集成测试进一步提高了代码质量和可靠性。这些收获让我们更专注于业务逻辑处理,降低了对DOM操作的关注,提高了开发效率。总结来说,数据驱动视图的开发模式在现代Web开发中具有显著优势,能够提高开发效率、加强页面交互体验,并且使得前端代码更加清晰、易于维护。