Vue 条件渲染,列表渲染,key的作用和原理,列表过滤,列表排序,Vue监测数据原理和注意事项
Posted IT_Holmes
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue 条件渲染,列表渲染,key的作用和原理,列表过滤,列表排序,Vue监测数据原理和注意事项 相关的知识,希望对你有一定的参考价值。
文章目录
1. 条件渲染
使用v-show做条件渲染,使用v-if做条件渲染,v-if是连结构也能消除的。
v-if,v-else-if,v-else是一起的。其中有一个验证成功,其他的就不会验证了。注意这些内容必须紧紧靠在一起!!
但在这我们可以用template实现。不会破坏dom结构 ,此外template不能和v-show配合。
源码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=
, initial-scale=1.0">
<title>条件渲染</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<style>
/* h2{
visibility: hidden;
color: transparent;
display: none;
以上这些都可以达到不显示的效果。
} */
</style>
</head>
<body>
<div id="root">
<!-- 使用v-show做条件渲染 -->
<!-- v-show为true显示,为false隐藏。 -->
<h2 v-show="false">欢迎来到,{{name}}</h2>
<h2 v-show="1 === 1">欢迎来到,{{name}}</h2>
<hr>
<!-- 使用v-if做条件渲染,v-if是连结构也能消除的 -->
<h2 v-if="false">欢迎来到,{{name}}</h2>
<h2 v-if="1 === 1">欢迎来到,{{name}}</h2>
<hr>
<h2>当前的n值为:{{n}}</h2>
<button @click="n++">n加1</button>
<!-- v-if,v-else-if,v-else是一起的。其中有一个验证成功,其他的就不会验证了。注意这些内容必须紧紧靠在一起!! -->
<div v-if=" n === 1">Angular</div>
<div v-else-if=" n === 2">React</div>
<div v-else-if=" n === 3">Vue</div>
<div v-else>哈哈</div>
<hr>
<!-- 对于存在多个的标签我们可以定义div来实现,但这种实现修改了dom结构。 -->
<div v-if="n === 1">
<h2>你好</h2>
<h2>我是</h2>
<h2>div</h2>
</div>
<!-- 但在这我们可以用template实现。不会破坏dom结构 ,此外template不能和v-show配合。-->
<template v-if="n===1">
<h2>你好</h2>
<h2>我是</h2>
<h2>template</h2>
</template>
</div>
<script>
Vue.config.productionTip = false;
const vm = new Vue({
el:"#root",
data:{
name:"北京大学",
n:0
}
});
</script>
</body>
</html>
2. 列表渲染
形式上分为下面几种:
使用v-for遍历数组。
使用v-for遍历对象。
遍历字符串 (用的少)。
遍历指定次数 (用的少)。
注意事项:
一定注意下面的注释,value,key,index的各个关系位置,搞清楚!!
源码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>列表渲染</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="root">
<!-- 使用v-for遍历数组 -->
<h2>人员列表(遍历数组)</h2>
<ul>
<!-- 这里的p和index指的就是内容和索引值,此外这里的key我们可以用index来区分,也可以用p.id这样的形式来。 -->
<li v-for="(p,index) in persons" :key="index">{{p.name}}-{{p.age}} ---索引值:{{index}}</li>
<hr> <!--这里的in也可以用of来对待一样的效果 -->
<li v-for="(p,index) in persons" :key="p.id">{{p.name}}-{{p.age}} ---索引值:{{index}}</li>
</ul>
<!-- 使用v-for遍历对象 -->
<!-- 对象这里的value和key的相关了 -->
<h2>汽车信息(遍历对象)</h2>
<ul>
<li v-for="(value,key) in car" :key="key">value:{{value}}} ---key:{{key}}</li>
</ul>
<!-- 遍历字符串 (用的少)-->
<h2>遍历字符串</h2>
<ul>
<li v-for="(char,index) in str" :key="index">{{char}}----{{index}}</li>
</ul>
<!-- 遍历指定次数 (用的少)-->
<h2>遍历指定次数</h2>
<ul>
<li v-for="(number,index) in 5" :key="index">{{number}}----{{index}}</li>
</ul>
</div>
<script>
Vue.config.productionTip = false;
new Vue({
data:{
persons:[
{id:"001",name:"张三",age:18},
{id:"002",name:"李四",age:19},
{id:"003",name:"王五",age:20}
],
car:{
name:"奥迪",
price:"70w",
color:'黑色'
},
str:'hello'
}
}).$mount('#root');
</script>
</body>
</html>
3. key的作用和原理
需要我们注意的是,在我们定义key时,使用index和id的这种作法有什么区别,什么使用用index?什么使用用id?
注意事项:
如果没有定义key属性,默认就是index作为key的值,作为唯一标识。
3.1 index作为key 的效果和问题
一定理解好虚拟DOM和真实DOM,以及中间的虚拟DOM对比算法。
上图对比虚拟DOM时,对比了三部分,第一个key,第二个内容(张三–18),第三个input标签。大体上就这样一步步对比,在这key作为唯一标识,内容不同就会覆盖。注意这里我们添加的时真实DOM中的input,在虚拟dom中input还是一样的,因此直接会使用真实DOM中的内容。
这里使用index来操作的话,就会出现这种问题:
源码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>列表渲染</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="root">
<h2>人员列表(遍历数组)</h2>
<button v-on:click.once="add">添加个人</button>
<ul>
<li v-for="(p,index) in persons" :key="index">
{{p.name}}-{{p.age}} ---索引值:{{index}}
<input type="text">
</li>
</ul>
</div>
<script>
Vue.config.productionTip = false;
new Vue({
data:{
persons:[
{id:"001",name:"张三",age:18},
{id:"002",name:"李四",age:19},
{id:"003",name:"王五",age:20}
]
},
methods: {
add(){
const p = {id:'004',name:'老李',age:"30"};
this.persons.unshift(p); //unshift(xxx),将xxx插入 arrayObject 的头部,并将已经存在的元素顺次地移到较高的下标处,以便留出空间
}
},
}).$mount('#root');
</script>
</body>
</html>
点击添加个人后,就会出现下面这样的问题。
一定注意index这样类似的改变顺序的错误。
3.1 id作为key 的效果(最佳)
使用id来实现,就可以避免上面index所出现的问题。
源码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>列表渲染</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="root">
<h2>人员列表(遍历数组)</h2>
<button v-on:click.once="add">添加个人</button>
<ul>
<li v-for="(p,index) in persons" :key="p.id">
{{p.name}}-{{p.age}} ---索引值:{{index}}
<input type="text">
</li>
</ul>
</div>
<script>
Vue.config.productionTip = false;
new Vue({
data:{
persons:[
{id:"001",name:"张三",age:18},
{id:"002",name:"李四",age:19},
{id:"003",name:"王五",age:20}
]
},
methods: {
add(){
const p = {id:'004',name:'老李',age:"30"};
this.persons.unshift(p); //unshift(xxx),将xxx插入 arrayObject 的头部,并将已经存在的元素顺次地移到较高的下标处,以便留出空间
}
},
}).$mount('#root');
</script>
</body>
</html>
3.3 两个总结
4. 列表过滤
4.1 通过watch,filter和indexOf()来实现
我们通过使用Vue,来实现一个模糊查询。通过watch,filter和indexOf来实现,一定注意indexOf在空字符串情况下怎么操作的。
源码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>列表渲染</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="root">
<h2>人员列表</h2>
<input type="text" placeholder="请输入名字" v-model="keyWord">
<ul>
<li v-for="(p,index) in filePersons" :key="index">
{{p.name}}-{{p.age}}-{{p.sex}}
</li>
</ul>
</div>
<script>
Vue.config.productionTip = false;
new Vue({
data:{
keyWord:'',
persons:[
{id:"001",name:"马冬梅",age:18,sex:"女"},
{id:"002",name:"周冬雨",age:19,sex:"女"},
{id:"003",name:"周杰伦",age:20,sex:"男"},
{id:"004",name:"温兆伦",age:20,sex:"男"}
],
filePersons:[]
},
watch:{
//通过监视keyWord来实现功能。
keyWord:{
//这里的immediate和indexOf相结合可以完美达到在页面显示的内容。
//immediate会先调用一下handler函数,同时indexOf在val为空字符串的情况下,刚好可以得到所有内容。
immediate:true,
handler(val){
console.log("修改了");
this.filePersons = this.persons.filter((p)=>{
return p.name.indexOf(val) !== -1;
//注意indexOf()如果不包含返回-1,包含返回对应的索引值。
//此外,我们定义空字符串也是包含的,索引值为0.
});
}
}
}
}).$mount('#root');
</script>
</body>
</html>
4.2 通过使用computed,filter和indexOf()来实现
#region和#endregion,这两个可以将注释的内容折叠起来。
computed比watch要简单一些,推荐使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>列表渲染</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="root">
<h2>人员列表</h2>
<input type="text" placeholder="请输入名字" v-model="keyWord">
<ul>
<li v-for="(p,index) in filePersons" :key="index">
{{p.name}}-{{p.age}}-{{p.sex}}
</li>
</ul>
</div>
<script>
Vue.config.productionTip = false;
new Vue({
data:{
keyWord:'',
persons:[
{id:"001",name:"马冬梅",age:18,sex:"女"},
{id:"002",name:"周冬雨",age:19,sex:"女"},
{id:"003",name:"周杰伦",age:20,sex:"男"},
{id:"004",name:"温兆伦",age:20,sex:"男"}
],
},
computed:{
filePersons(){
//需要给filePersons返回我们过滤后的结果。
return this.persons.filter((p)=>{
//这里的return是返回的filter函数中的值。
//此外我们可以用this.keyWord来替代。
return p.name.indexOf(this.keyWord) !== -1;
});
}
}
}).$mount('#root');
new Vue
</script>
</body>
</html>
5. 列表排序
需要注意的是sort()函数判断a-b升序,b-a降序。以及下面所实现的形式。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>列表渲染</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="root">
<h2>人员列表</h2>
<input type="text" placeholder="请输入名字" v-model="keyWord">
<button @click="sortType = 2">年龄升序</button>
<button @click="sortType = 1">年龄降序</button>
<button @click="sortType = 0">原顺序</button>
<ul>
<li v-for="(p,index) in filePersons" :key="index">
{{p.name}}-{{p.age}}-{{p.sex}}
</li>
</ul>
</div>
<script>
Vue.config.productionTip = false;
new Vue({
data:{
keyWord:'',
sortType:0,
persons:[
{id:"001",name:"马冬梅",age:30,sex:"女"},
{id:"002",name:"周冬雨",age:21,sex:"女"},
{id:"003",name:"周杰伦",age:23,sex:"男"},
{id:"004",name:"温兆伦",age:20,sex:"男"}
],
},
computed:{
filePersons(){
//需要给filePersons返回我们过滤后的结果。
const arr = this.persons.filter((p)=>{
//这里的return是返回的filter函数中的值。
//此外我们可以用this.keyWord来替代。
return p.name.indexOf(this.keyWord) !== -1;
});
// 判断一下是否需要排序
if(this.sortType){
//sort()函数判断a-b升序,b-a降序。
arr.sort((a,b)=>{
return this.sortType === 1 ? b.age-a.age : a.age-b.age;
});
}
return arr;
}
}
}).$mount('#root');
new Vue
</script>
</body>
</html>
6. 深度了解Vue如何监测data对象中的数据改变
需要了解一下Observer对象和它的构造函数。下面我们重写一下它的Observer。
我们平时所看到的vm._data的本质就是Observer对象。
源码:
通过Observer来模拟一下,data和vm._data,obs之间的一个数据监测(被修改什么的)。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
let data = {
name:"清华大学",
address:"北京"
}
//通过Observer来模拟一下,data和vm._data,obs之间的一个数据监测(被修改什么的)。
const obs = new Observer(data);
console.log(obs);
let vm = {};
vm._data = data = obs;
function Observer(obj){
//Object.keys(xxx)可以汇总xxx对象中的所有的属性形成一个数组
const keys = Object.keys(obj);
keys.forEach((k)=>{
Object.defineProperty(this,k,{
get(){
return obj[k];
},
set(val){
console.log(`${k}被修改了,我要去解析模板,生成虚拟DOM...我要开始了`)
obj[k] = val;
}
})
})
}
</script>
</body>
</html>
上面的代码虽然实现了,监测data中的数据变化,但是如果遇到对象中包含对象,数组等特例(见下图),就不行了,但Vue中的监视原理就是这样的。这里我们只是了解一下他的特性而已。
7. Vue中set方法使用的方式和注意事项
在这具体的set修改方式有两种:如下图一样:
1. Vue.set(vm._data.student.‘sex’,‘男’)
2. vm.$set(vm._data.student,‘sex’,‘女’)
因为上面的vm._data.student 和vm.student 是数据代理的,所以他们两个是一样的。
因此,我们直接就可以写vm.student来设置属性什么的了。
源码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<title>Document</title>
</head>
<body>
<div id="root">
<h1>学校信息</h1>
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
<h2>班主任:{{leader}}</h2>
<hr>
<h1>学生信息</h1>
<button @click = 'addSex'>添加一个性别属性,默认为男</button>
<h2>学生姓名:{{student.name}}</h2>
<h2 v-if="student.sex">学生性别:{{student.sex}}</h2>
<h2>学生年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}</h2>
<h2>朋友们</h2>
<ul>
<li v-for="(f,index) in student.friends" :key="index">
{{f.name}} -- age:{{f.age}}
</li>
</ul>
</div>
</body>
<script>
Vue.config.productionTip = false;
const vm = new Vue({
el:"#root",
data:{
name:"清华大学",
address:"北京",
student:{
name:'tom',
sex:undefined,
age:{
rAge:40,
sAge:29
},
friends:[
{name:'jerry',age:35},
{name:"tony",age:36}
]
}
},
methods: {
addSex(){
//我们可以直接用这两种方式来定义怎加属性。
// Vue.set(this.student,'sex','男');
this.$set(this.student,"sex",'女');
}
},
});
</script>
</html>
我们直接给data对象设置属性,是不可以的!!!
8. Vue 对于data中数组的监测原理和注意事项
对于数组Vue并没有给他们生成一定的get和set。
既然没有get和set,那如何得到响应监测的目的呢?
可能最先想到的就是通过索引值的方法来达到效果,这样是直接修改了数组,页面并不会监测到!!也就是页面并不会变化!
解决上面的问题办法就是通过下面的这7个方法,调用它们操作数组来达到监测效果。
注意事项:
这里的push和array.prototype.push是不一样的。前者是被Vue管理的push。被Vue管理的push包含了array.prototype.push的原始功能,还包装了一些类似重新解析模板的一些功能。
除了上面的7个数组的方法可以监测修改,还可以通过Vue.set()和vm.$set()来操作修改,也是没问题的。
注意事项:
数组中的对象的属性是包含get和set,因此数组中对象本身是没有get和set监视,但对象内部属性有get和set。如下图:
9. 数据监测总结
数据劫持就是将原来data内的数据,加工成了vm._data这样的数据的过程叫做数据劫持,因为中间给它添加了很多Vue方面的功能。
以上是关于Vue 条件渲染,列表渲染,key的作用和原理,列表过滤,列表排序,Vue监测数据原理和注意事项 的主要内容,如果未能解决你的问题,请参考以下文章
Vue中使用v-for渲染数据为何要添加key属性?(原理及作用)