总结问题
写在前面
①调用对象的时候使用this.不要忘了,
②不允许出现双等号以及判断用三等号为空为true或者false
③$set数据,单独为变量赋值,一般用于数组里面的数据,因为深层遍历,可能会出现数据变了但是dom没有刷新,原因是vue不会监听内层的东西
④template可以不渲染成任何标签,有些地方会要求到不可以有什么标签之类的⑤span不换行div换行,文件命名规范是sdd-user,都是小写
关于整体架构
首先我们建立的是一个html文件
然后我们要导入vue.js,把它和html文件放在同一目录下
<script src="vue.js"></script>
然后定义一个div实现vue实例的作用域,这个包含所有的template,即html标签
<div id="app"></div>
然后在
const app = new Vue({
el: "#app",
data:{},
methods:{},
computed:{},
})
关于html标签
表示表单,所以如果有button就会提交,页面就会刷新 表示表格:border="1"显示表格的线 tr表示一行 th表示表格的表头 td表示一个单元格 br表示换行 p表示段落- (无序列表) 和
- (列表项):
- 标签用于创建一个无序列表,其中的项目用
- 标签表示。这些项目通常以小圆点进行标记。
- 标签嵌套在
- 标签内部,用于定义列表中的各个项目。 ## 1.v-model的值 如果data中定义了user如下代码: ```javascript user:{ name: '', age: '', email: '', Checked:'', isEditing:false, }, ``` 那么在输入框input中v-model可以直接绑定user.name等,不需要再在data中定义name等属性 即:
<input type="text" v-model="user.name" @blur="showNametip"/>
==注意:v-model就是这个input里面的值,相当于 v-bind:value=“user.name” + @input=“user.name” ==
在后面修改功能的时候,点击修改按钮,前面的信息变成输入框input的形式,在这个标签里面v-model的值就是包含了value即初始显示的值,所以说不需要设置value
2.关于事件监听和失去焦点
监听事件通常指的是使用v-on指令来绑定事件监听器到视图上的元素。当这些元素上的事件被触发时,相应的回调函数就会被调用。
失去焦点指的是一个元素不再接收用户输入或交互命令的状态。当一个文本框、按钮或其他交互式元素获得焦点时,用户可以通过键盘输入或点击来与之交互。而当这个元素失去焦点时,用户的输入或交互将不再影响这个元素,而是转移到其他可接收焦点的元素。
== 注意 不是 监听元素的点击事件@click==
<input type="text" v-model="user.name" @blur="showNametip"/>
<p class="red" v-if="flag1">请输入姓名</p>
showNametip是一个方法,它会在输入框失去焦点时被调用
判断输入框内是否是空,不是空就不需要显示提示信息
data: {
flag1: true,
}
methods: {
showNametip() {
if(this.user.name!== ""){
this.flag1 = false
}
},
}
3.正则校验
使用test,返回true\false
<p class="red" v-if="!isValidAge">请输入正确年龄</p>
计算属性:
computed:{
isValidAge(){
const numberUp =/^(?:[1-9][0-9]?|1[01][0-9]|120)$/
return numberUp.test(this.user.age)
},
4.关于提交,也就是注册,添加 和重置
<button type="button" @click="add()">提交</button>
<button type="reset" >重置</button>
这里的add函数我们要增加校验,
1.非空校验,三个元素分别非空,另外就是关于年龄和邮箱的正则校验
2.姓名的验重,这里我们用的是es6中的对于数组处理的方法some
this.数组.some(数组中的item写啥都行只是形参=> item.name === this.user.name)
这样就能够根据true、false来判断是否有重名的
校验完成之后就可以添加用户了,使用push
this.users.push({…this.user})
== 这里有一个大问题,就是push的对象,如果push的是this.user的话,那么说它指向的是同一个内存地址,所以如果这样,假设我们把一个用户的信息添加多次在没有验重的情况下,后续就会导致修改任意一个元素,输入框里的元素也会修改,就是点击修改按钮也是所有的元素同时修改,以及复选框也是同时选中。
使用{…this.user}:这是一个对象字面量,使用扩展运算符(…)来复制 this.user 对象。扩展运算符用于取出一个数组或对象中的元素,并作为独立的元素返回。在这里,它用于复制 this.user 对象,以便将复制后的对象添加到 users 数组中。==
add() {
const numberUp = /^(?:[1-9][0-9]?|1[01][0-9]|120)$/
const regEmail = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/
if((this.user.name!=='')&&(this.user.age!=='')&&(this.user.email!=='')&&(numberUp.test(this.user.age))&&(regEmail.test(this.user.email))) {
if(!this.users.some(user=> user.name === this.user.name)){
this.users.push({...this.user})
this.isnull = false
}
// for(let i=0;i<=this.users.length;i++) {
// if(i === 0){
// this.users.push(this.user)
// //this.user={}
// this.isnull = false
// }
// else if (this.user.name !=this.users[i].name) {
// this.users.push(this.user)
// }
// }
}
},
5.关于v-for的实际用法----根据前面已经知道当输入一条用户信息就会增加到数组中,那么如果要展示到表格中我们对数组进行遍历就可以一条条显示到表格,由于数据是双向绑定的,所以可以实时改变
item就是一个对象
<tr v-for="(item, index) in users" :key='index'>
<tr>
6.关于修改
一开始最大瓶颈就是如何实现点击按钮之后,前面的表格信息变成输入框input形式,并且修改按钮变成保存按钮,解决方法就是使用v-if和v-else
写在前面:修改实际就是编辑状态的改变,编辑状态为true时就展示输入框,为false时就展示数据
首先理一下思路,我们这一行数据是放到v-for中的,在此我们定义的users中的对象是item(形参名),也就是说接下来我们要用这个参数来调用一些数据,所以第一点,v-model绑定的是item.Checked、item.name、item.age、item.email
然后就是如何控制点击按钮的时候的转变,点击修改按钮,我们设置一个标志如果是编辑状态(值为true、false)我们就显示输入框如果不是就正常显示,对于table中的每一条数据都是这样,所以可以将这个标志写道我们这个user对象的属性里,所以可以用到v-if和v-else
按钮是相同的道理,根据编辑状态进行展示。
<td><input type="checkbox" v-model="item.Checked" /></td>
<td>
{{index + 1 }}
</td>
<td>
<div v-if="item.isEditing">
<input type="text" v-model="item.name" >
</div>
<div v-else>
{{item.name}}
</div>
</td>
<td>
<div v-if="item.isEditing">
<input type="text" v-model="item.age" >
</div>
<div v-else>
{{item.age}}
</div>
</td>
<td>
<div v-if="item.isEditing">
<input type="text" v-model="item.email">
</div>
<div v-else>
{{item.email }}
</div>
</td>
<td>
<div v-if="item.isEditing">
<button @click="save(index)">保存</button>
<button @click="del(index)">删除</button>
</div>
<div v-else>
<button type="button" @click="edit(item)">修改</button>
<button @click="del(index)">删除</button>
</div>
</td>
</tr>
注意因为前面我们在v-for中遍历取了item,所以在函数里我们可以直接用item这个对象
edit(item) {
item.isEditing = true
console.log(this.users)
},
7.关于保存
写在前面:保存也是编辑状态的改变,当我们处于编辑状态true的时候,这个时候保存按钮出来,点击按钮触发事件函数,增加一些校验,再把编辑状态改为false,这就是完成了保存
赋值对象的某个属性 Object.key=value 但是页面视图没有刷新 可以改用this.$set(Object,‘key’,value) 来赋值。
this.$set(item, ‘isEditing’, false)
save(item){
const numberUp = /^(?:[1-9][0-9]?|1[01][0-9]|120)$/
const regEmail = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/
if((item.name!=='')&&(item.age!=='')&&(item.email!=='')&&(numberUp.test(item.age))&&(regEmail.test(item.email))&&(numberUp.test(item.age))&&(regEmail.test(item.email))) {
// if (!this.users.some(user => user.name === item.name)) {
this.$set(item, 'isEditing', false)
alert("保存成功")
//}
// for(let i=0;i<this.users.length;i++){
// if(this.users[index].name!=this.users[i].name){
// this.users[index].name=this.item.name
// this.users[index].age=this.item.age
// this.users[index].email=this.item.email
//
// this.users[index].isEditing=false
// }
//
// }
}
},
8.删除
删除比较简单
del(index) {
this.users.splice(index, 1);
},
8.关于复选框以及全选
复选框checkbox
<input type="checkbox" v-model="allChecked" />
<input type="checkbox" v-model="item.Checked" />
全选
涉及到计算属性:
在Vue.js中,计算属性(computed properties)是一种基于它们的响应式依赖进行缓存的计算值。这意味着只有当计算属性依赖的响应式数据发生变化时,计算属性的值才会重新计算。计算属性非常适用于需要复杂逻辑计算的情况,同时保持性能和响应性。
allChecked是一个计算属性,它用于表示所有用户是否都被选中。这里是如何工作的:
**设置值(Setter):**当allChecked的值被设置时,set函数会被调用。在这个函数中,你通过遍历users数组,将每个用户的checked属性设置为新的值(val)。这意味着如果你想要选中所有用户,你可以将allChecked设置为true,这将导致users数组中每个用户的checked属性都变为true。
**取值(Getter):**当你需要获取allChecked的值时,get函数会被调用。在这个函数中,你使用filter方法来找出所有checked属性为true的用户,并检查这些用户的长度是否等于users数组的长度。如果所有用户都被选中,那么filter方法将返回一个包含所有用户的长度为users.length的数组,此时计算属性的值将为true;如果仍有用户未被选中,则返回的数组长度将小于users.length,计算属性的值将为false。
这样,通过allChecked计算属性,你可以方便地知道所有用户是否都被选中,而不需要手动计算。当你需要更新所有用户的选中状态时,可以通过设置allChecked的值来触发set函数,实现响应式地更新所有用户的checked属性。
allChecked: {
// 设置值
set(val) {
console.log(val);
this.users.forEach((item) => (item.Checked = val));
},
//取
get() {
return (
this.users.filter((item) => item.Checked).length ===
this.users.length
);
}
},
9.关于批量-点击批量保存是先执行失去焦点
就是判断复选框的值true或者false,如果时true的话就进行修改保存删除操作
使用for循环或者while循环就可以实现
全部删除就是把数组设置为空即可
deleteall(){
this.users=[]
this.isnull=true
},
deletesome(){
let i=this.users.length
while (i--){
if (this.users[i].Checked){
this.users.splice(i, 1)
}
}
},
editsome(){
let i=this.users.length
while (i--){
if (this.users[i].Checked){
this.users[i].isEditing = true
}
}
this.someEditing=true
},
savesome(){
const numberUp = /^(?:[1-9][0-9]?|1[01][0-9]|120)$/
const regEmail = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/
for (let i=0;i<this.users.length;i++) {
if (this.users[i].Checked === true) {
if ((this.users[i].name !== '') && (this.users[i].age !== '') && (this.users[i].email !== '') && (numberUp.test(this.users[i].age)) && (regEmail.test(this.users[i].email))) {
// if (!this.users.some(user => user.name === this.users[i].name)) {
this.$set(this.users[i], 'isEditing', false)
i++
// }
}
}
alert("保存成功")
this.someEditing = false
}
}
源码:
<!DOCTYPE html>
<html>
<head>
<script src="vue.js"></script>
<meta charset="utf-8" />
<title>用户信息</title>
</head>
<body>
<div id="app">
<form>
<tr>
<h1>添加用户</h1>
<td class="red">*</td>
<th >姓名:</th>
<input type="text" v-model="user.name" @blur="showNameTip($event)"/>
<p class="red" v-if="inputemptyname">请输入姓名</p>
<p class="red" v-if="repeat">姓名重复</p>
</tr>
<br>
<tr>
<td class="red">*</td>
<td >年龄:</td>
<input type="text" v-model="user.age" @blur="showAgeTip($event)"/>
<p class="red" v-if="inputemptyage">请输入年龄</p>
<p class="red" v-if="!isValidAge">请输入正确年龄</p>
</tr>
<br>
<tr>
<td class="red">*</td>
<td >邮箱:</td>
<input type="text" v-model="user.email" @blur="showEmailTip($event)"/>
<p class="red" v-if="inputemptyemail">请输入邮箱</p>
<p class="red" v-if="!isValidEmail">请输入正确邮箱</p>
</tr>
<br>
<tr>
<button type="button" @click="add()">提交</button>
<button type="reset" @click="reset()">重置</button>
</tr>
</form>
<h1>----------------------------------------------------------</h1>
<h1>用户列表</h1>
<div class="contariner">
<table border="1" cellpadding="1" cellspacing="2">
<tr>
<th><input type="checkbox" v-model="allChecked" /></th>
<th>序号</th>
<th>姓名</th>
<th>年龄</th>
<th>邮箱</th>
<th>操作</th>
</tr>
<tr v-for="(item, index) in users" :key='index'>
<td><input type="checkbox" v-model="item.checked" /></td>
<td>
{{item.id=index + 1 }}
</td>
<td>
<div v-if="item.isEditing">
<input type="text" v-model="item.name" @blur="modifyName(item)">
<div class="red" v-show="item.modifyemptyname">请输入姓名</div>
<div class="red" v-if="item.modifyRepeat">姓名重复</div>
</div>
<div v-else>
{{item.name}}
</div>
</td>
<td>
<div v-if="item.isEditing">
<input type="text" v-model="item.age" @blur="modifyAge(item)">
<div class="red" v-show="item.modifyemptyage">请输入年龄</div>
<div class="red" v-show="item.modifyAgeNo">请输入正确年龄</div>
</div>
<div v-else>
{{item.age}}
</div>
</td>
<td>
<div v-if="item.isEditing">
<input type="text" v-model="item.email" @blur="modifyEmail(item)">
<div class="red" v-show="item.modifyemptyemail">请输入邮箱</div>
<p class="red" v-show="item.modifyEmailNo">请输入正确邮箱</p>
</div>
<div v-else>
{{item.email }}
</div>
</td>
<td>
<div v-if="item.isEditing">
<button @click="save(item)">保存</button>
<button @click="del(index)">删除</button>
</div>
<div v-else>
<button type="button" @click="edit(item)">修改</button>
<button @click="del(index)">删除</button>
</div>
</td>
</tr>
<tr>
<td>
<div v-if="isNull">暂无数据</div>
<div v-else>
<button type="button" @click="deleteAll">全部删除</button>
<button type="button" v-show="delSelect" @click="deleteSome">批量删除</button>
<button type="button" v-show="editSelect" @click="editSome">批量修改</button>
<button type="button" v-show="saveSelect" @click="saveSome">批量保存</button>
</div>
</td>
</tr>
</table>
</div>
<h2 class="red">*用户列表内用户姓名不能重复*</h2>
</div>
</body>
<script>
const app = new Vue({
el: "#app",
data: {
inputemptyname:false,
inputemptyage:false,
inputemptyemail:false,
repeat:false,
isValidEmail:true,
isValidAge:true,
user:{
id:'',
name: '',
age: '',
email: '',
checked:'',
isEditing:false,
modifyemptyname:false,
modifyemptyage:false,
modifyemptyemail:false,
modifyAgeNo:false,
modifyEmailNo:false,
modifyRepeat:false,
},
users: [],
},
methods: {
showNameTip(event) {
if (!event.target.value){
this.inputemptyname=true
this.repeat=false
//console.log(modifyemptyname)
}else{
this.inputemptyname=false
if (this.users.some(user => event.target.value=== user.name)){
this.repeat=true
}else{
this.repeat=false
}
}
},
showAgeTip(event) {
const numberUp =/^(?:[1-9][0-9]?|1[01][0-9]|120)$/
if (!event.target.value){
this.inputemptyage=true
this.isValidAge=true
//console.log(modifyemptyname)
}else{
this.inputemptyage=false
if (numberUp.test(this.user.age)){
this.isValidAge=true
}else{
this.isValidAge=false
}
}
},
showEmailTip(event) {
const regEmail = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/
if (!event.target.value){
this.inputemptyemail=true
this.isValidEmail=true
}else{
this.inputemptyemail=false
if (regEmail.test(this.user.email)){
this.isValidEmail=true
}else{
this.isValidEmail=false
}
}
},
add() {
const numberUp = /^(?:[1-9][0-9]?|1[01][0-9]|120)$/
const regEmail = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/
if(!this.user.name){this.inputemptyname=true}
if(!this.user.age){this.inputemptyage=true}
if(!this.user.email){this.inputemptyemail=true}
if((this.user.name)&&(this.user.age)&&(this.user.email)&&(numberUp.test(this.user.age))&&(regEmail.test(this.user.email))) {
if(!this.users.some(user=> user.name === this.user.name)){
this.users.push({...this.user})
this.user={
id:'',
name: '',
age: '',
email: '',
checked:'',
isEditing:false,
modifyemptyname:false,
modifyemptyage:false,
modifyemptyemail:false,
modifyAgeNo:false,
modifyEmailNo:false,
modifyRepeat:false,
}
}
}
},
//重置保存按钮触发事件
reset(){
this.inputemptyname=false
this.inputemptyage=false
this.inputemptyemail=false
},
//编辑按钮触发事件
edit(item) {
item.isEditing = true
console.log(this.users)
},
//保存按钮触发事件
//因为是双向绑定,所以说item里的数据改变了this.users里面的数据也发生改变
save(item){
const numberUp = /^(?:[1-9][0-9]?|1[01][0-9]|120)$/
const regEmail = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/
if((item.name)&&(item.age)&&(item.email)&&(numberUp.test(item.age))&&(regEmail.test(item.email))&&(numberUp.test(item.age))&&(regEmail.test(item.email))) {
if (this.users.filter(user1 =>user1.id!==item.id).some(user2 => item.name=== user2.name)){
this.$set(item, 'modifyRepeat', true)
}else {
this.$set(item, 'isEditing', false)
}
}
},
//删除按钮触发事件
del(index) {
this.users.splice(index, 1);
},
//删除全部按钮触发事件
deleteAll(){
this.users=[]
},
//批量删除按钮触发事件
deleteSome(){
let i=this.users.length
while (i--){
if (this.users[i].checked){
this.users.splice(i, 1)
}
}
},
//批量编辑按钮触发事件
editSome(){
let i=this.users.length
while (i--){
if (this.users[i].checked){
this.users[i].isEditing = true
}
}
},
//批量保存按钮触发事件
saveSome(){
for (let i=0;i<this.users.length;i++) {
if (this.users[i].checked) {
this.save(this.users[i])
}
}
console.log(this.users)
},
//修改名字时的失去焦点事件
modifyName(item){
if (!item.name){
item.modifyemptyname=true
item.modifyRepeat=false
}else{
item.modifyemptyname=false
if (this.users.filter(user1 =>user1.id!==item.id).some(user2 => item.name=== user2.name)){
item.modifyRepeat=true
}else{
item.modifyRepeat=false
}
}
},
//修改年龄时的失去焦点事件
modifyAge(item){
const numberUp = /^(?:[1-9][0-9]?|1[01][0-9]|120)$/
if (!item.age){
item.modifyemptyage=true
item.modifyAgeNo=false
}else {
item.modifyemptyage=false
if (!numberUp.test(item.age)){
item.modifyAgeNo=true
}else {
item.modifyAgeNo=false
}
}
},
//修改邮箱时的失去焦点事件
modifyEmail(item){
const regEmail = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/
if (!item.email){
item.modifyemptyemail=true
item.modifyEmailNo=false
}else {
item.modifyemptyemail=false
if (!regEmail.test(item.email)){
item.modifyEmailNo=true
}else {
item.modifyEmailNo=false
}
}
},
},
computed:{
//计算复选框选中大于一的时候出现批量删除按钮
delSelect(){
let count=0
let selectUsers=this.users.filter(user =>user.checked)
if (selectUsers.length > 0) {
return true
}
},
//计算复选框选中都是非编辑状态且大于一的时候出现批量编辑按钮
editSelect(){
let count=0
let selectUsers=this.users.filter(user =>user.checked)
if (selectUsers.every(user => !user.isEditing )) {
if (selectUsers.length > 0) {
return true
}
}
},
//计算复选框选中都是非编辑状态且大于一的时候出现批量按钮
saveSelect(){
let count=0
let selectUsers=this.users.filter(user =>user.checked)
if (selectUsers.every(user => user.isEditing)) {
if (selectUsers.length > 0) {
return true
}
}
},
//计算users没有元素的时候出现暂无数据
isNull(){
if(this.users.length===0){
return true
}
},
//计算全选时其他的复选框也为true;当其他复选框全部选中时返回true
allChecked: {
// 设置值
set(val) {
console.log(val);
this.users.forEach((item) => (item.checked = val));
},
//取
get() {
if(this.users.length===0){
return false
}else{
return this.users.filter((item) => item.checked).length ===this.users.length
}
}
},
},
});
</script>
<style>
.red {
color: red;
}
</style>
</html>