目录
- 一、v-for指令
-
- [1.1 遍历数组](#1.1 遍历数组)
- [1.2 遍历对象](#1.2 遍历对象)
- [1.3 遍历字符串](#1.3 遍历字符串)
- [1.4 遍历指定次数](#1.4 遍历指定次数)
- [1.5 案例整合](#1.5 案例整合)
- 二、key的作用与原理
-
- [2.1 虚拟DOM中key的作用](#2.1 虚拟DOM中key的作用)
- [2.2 新旧虚拟DOM对比规则](#2.2 新旧虚拟DOM对比规则)
- [2.3 用index作为key可能会引发的问题](#2.3 用index作为key可能会引发的问题)
-
- [2.3.1 错误案例](#2.3.1 错误案例)
- [2.3.2 错误效果](#2.3.2 错误效果)
- [2.3.3 错乱原理图](#2.3.3 错乱原理图)
- [2.4 开发中如何选择key?](#2.4 开发中如何选择key?)
- 三、列表过滤
-
- [3.1 watch实现](#3.1 watch实现)
- [3.2 computed计算属性实现](#3.2 computed计算属性实现)
- 四、列表排序
-
- [4.1 需求](#4.1 需求)
- [4.2 实现](#4.2 实现)
一、v-for指令
- 用于展示列表数据
- 语法 :
v-for="(item, index) in/of xxx" :key="yyy"
- 可遍历:数组、对象、字符串、指定次数。
1.1 遍历数组
下面案例中,定义了一个数组persons
, 我们使用v-for
指令进行遍历,遍历的次数即为数组的长度length
。
接受的参数有两个,一个是数组中的每一项p
,另一个参数为数组的索引值index
,并用:key
动态指定每一项的唯一标识key
。
注意 :这里的唯一标识key
不会在真实DOM
上,但是会在Vue
生成的虚拟DOM
上。在用DIFF
算法的时候会用到。
具体代码如下所示:
html
<div id="root">
<ul>
<li v-for="(p,index) in persons" :key="index">
{{p.name}} - {{p.use}}
</li>
</ul>
</div>
<script>
new Vue({
el:'#root',
data:{
persons:[
{id:'001',name:'令狐冲',use:"独孤九剑"},
{id:'002',name:'任盈盈',use:"仙女下凡"},
{id:'003',name:'任我行',use:"吸星大法"}
]
}
})
</script>
1.2 遍历对象
下面案例中,定义了一个对象person
, 我们使用v-for
指令进行遍历,遍历的次数即为对象的属性的个数。
接受的参数有两个,一个是对象中的每个属性的值value
,另一个参数为对象的属性名key
,并用:key
动态指定每一项的唯一标识key
。
html
<div id="root">
<ul>
<li v-for="(value,key) of person" :key="key">
{{key}} - {{value}}
</li>
</ul>
</div>
<script>
new Vue({
el:'#root',
data:{
person:{
name:'令狐冲',
use:'独孤九剑',
menpai:'华山派'
}
}
})
</script>
1.3 遍历字符串
下面案例中,定义了一个字符串str
, 我们使用v-for
指令进行遍历,遍历的次数即为字符串的字符个数。
接受的参数有两个,一个是字符串中的每个字符值char
,另一个参数为字符串的索引index
,并用:key
动态指定每一项的唯一标识key
。
html
<div id="root">
<ul>
<li v-for="(char,index) of str" :key="index">
{{index}} - {{char}}
</li>
</ul>
</div>
<script>
new Vue({
el:'#root',
data:{
str:'笑傲江湖'
}
})
</script>
1.4 遍历指定次数
下面案例中,指定遍历次数为5
次,我们使用v-for
指令进行遍历。
接受的参数有两个,一个是数值number
,另一个参数为索引index
,并用:key
动态指定每一项的唯一标识key
。
html
<div id="root">
<ul>
<li v-for="(number,index) of 5" :key="index">
{{index}} - {{number}}
</li>
</ul>
</div>
1.5 案例整合
html
<div id="root">
<h2>遍历数组</h2>
<ul>
<li v-for="(p,index) in persons" :key="index">
{{p.name}} - {{p.use}}
</li>
</ul>
<h2>遍历对象</h2>
<ul>
<li v-for="(value,key) of person" :key="key">
{{key}} - {{value}}
</li>
</ul>
<h2>遍历字符串:'笑傲江湖'</h2>
<ul>
<li v-for="(char,index) of str" :key="index">
{{index}} - {{char}}
</li>
</ul>
<h2>遍历指定次数:5次</h2>
<ul>
<li v-for="(number,index) of 5" :key="index">
{{index}} - {{number}}
</li>
</ul>
</div>
<script>
new Vue({
el:'#root',
data:{
persons:[
{id:'001',name:'令狐冲',use:"独孤九剑"},
{id:'002',name:'任盈盈',use:"仙女下凡"},
{id:'003',name:'任我行',use:"吸星大法"}
],
person:{
name:'令狐冲',
use:'独孤九剑',
menpai:'华山派'
},
str:'笑傲江湖'
}
})
</script>
二、key的作用与原理
2.1 虚拟DOM中key的作用
key
是虚拟DOM
对象的唯一标识- 当状态中的数据发生变化时,
Vue
会根据【新数据
】生成【新的虚拟DOM
】 - 随后
Vue
进行【新虚拟DOM
】与【旧虚拟DOM
】的差异进行比较。
2.2 新旧虚拟DOM对比规则
-
旧虚拟DOM
中找到了与新虚拟DOM
相同的key
:ⅰ. 若【虚拟DOM】中内容没变,直接使用之前的【真实DOM】 ! ⅱ. 若【虚拟DOM】中内容变了,则生成【新的真实DOM】,随后替换掉页面中【之前的真实DOM】.
-
旧虚拟DOM
中未找到与新虚拟DOM
相同的key
ⅰ. 创建【新的真实DOM】,随后渲染到到页面。
2.3 用index作为key可能会引发的问题
-
若对数据进行:
逆序添加
、逆序删除
等破坏顺序
操作:ⅰ. 会产生没有必要的【真实DOM】更新==>界面效果没问题,但效率低。
-
如果结构中还包含输入类的DOM:
i . 会产生【错误DOM】更新==>界面有问题。
2.3.1 错误案例
html
<div id="root">
<h2>index作为key引发的问题</h2>
<button @click.once="add">在列表最前面:添加一个小六六</button>
<ul>
<li v-for="(p,index) in persons" :key="index">
{{p.name}} - {{p.use}}
<input type="text" >
</li>
</ul>
</div>
<script>
new Vue({
el:'#root',
data:{
persons:[
{id:'001',name:'令狐冲',use:"独孤九剑"},
{id:'002',name:'任盈盈',use:"仙女下凡"},
{id:'003',name:'任我行',use:"吸星大法"}
]
},
methods: {
add() {
this.persons.unshift({id:'004',name:'老六',use:'不会武功'})
}
},
})
</script>
2.3.2 错误效果
- 在浏览器中打开案例,之后在输入框中输入一些内容
- 点击添加按钮,此时会发现输入框已经错乱了。
2.3.3 错乱原理图
- 遍历列表
index
作为key
时,发生错乱原理图,如下所示:
- 遍历列表
id
作为key
时,为什么没有发生错乱原理图,如下所示:
2.4 开发中如何选择key?
- 最好使用每条数据的唯一标识作为
key
,比如id
、手机号
、身份证号
、学号
等唯一值
。 - 如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用
index
作为key
是没有问题的。
三、列表过滤
需求:做一个列表过滤功能,UI如下图所示。在输入框中输入内容实现下面列表的过滤显示。
3.1 watch实现
- 列表显示:使用
v-for
指令遍历数组persons
- 在
data
中定义属性filPersons
:存放过滤后的内容 - 使用数组
filter
方法实现过滤
html
<div id="root">
<h2>列表过滤</h2>
<input type="text" placeholder="请输入内容" v-model="keyWord">
<ul>
<li v-for="(p,index) in filPersons" :key="index" >
{{p.name}} - {{p.use}} - {{p.sex}}
</li>
</ul>
</div>
<script>
new Vue({
el:'#root',
data:{
keyWord:'',
persons:[
{id:'001',name:'令狐冲',use:"独孤九剑",sex:'男'},
{id:'002',name:'任盈盈',use:"仙女下凡",sex:'女'},
{id:'003',name:'任我行',use:"吸星大法",sex:'男'}
],
filPersons:[]
},
watch:{
keyWord:{
immediate:true,
handler(value){
this.filPersons = this.persons.filter((p)=>{
return p.name.indexOf(value)>=0
})
}
}
}
})
</script>
3.2 computed计算属性实现
- 列表显示:使用
v-for
指令遍历数组persons
- 定义计算属性
filPersons
:存放过滤后的内容 - 使用数组
filter
方法实现过滤
html
<div id="root">
<h2>列表过滤</h2>
<input type="text" placeholder="请输入内容" v-model="keyWord">
<ul>
<li v-for="(p,index) in filPersons" :key="index" >
{{p.name}} - {{p.use}} - {{p.sex}}
</li>
</ul>
</div>
<script>
new Vue({
el:'#root',
data:{
keyWord:'',
persons:[
{id:'001',name:'令狐冲',use:"独孤九剑",sex:'男'},
{id:'002',name:'任盈盈',use:"仙女下凡",sex:'女'},
{id:'003',name:'任我行',use:"吸星大法",sex:'男'}
]
},
computed:{
filPersons(){
return this.persons.filter((p)=>{
return p.name.indexOf(this.keyWord)!==-1
})
}
}
})
</script>
四、列表排序
4.1 需求
要求:在上述案例中,增加排序功能,分别为升序、降序功能
4.2 实现
- 定义
sortType
属性:2升序、1降序、0原顺序 - 数组
sort
方法:arr.sort(a,b)
,a-b
为升序,b-a
为降序
html
<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 filPersons" :key="p.id" >
{{p.name}} - {{p.use}} - {{p.age}}
</li>
</ul>
</div>
<script>
new Vue({
el:'#root',
data:{
keyWord:'',
sortType:0,
persons:[
{id:'001',name:'令狐冲',use:"独孤九剑",sex:'男',age:20},
{id:'002',name:'任盈盈',use:"仙女下凡",sex:'女',age:19},
{id:'003',name:'任我行',use:"吸星大法",sex:'男',age:50}
]
},
computed:{
filPersons(){
const arr = this.persons.filter((p)=>{
return p.name.indexOf(this.keyWord)!==-1
})
if(this.sortType) {
arr.sort((p1,p2)=>{
return this.sortType === 1 ? (p2.age - p1.age) : (p1.age - p2.age);
})
}
return arr;
}
}
})
</script>