1.v-for 展示列表数据
1.1v-for的用法
v-for指令:
1.用于展示列表数据
2.语法:v-for="(item, index) in xxx" :key="yyy" 也可以用 v-for="item in XXX",使用in也是可以的
3.可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)
<!-- 遍历数组的写法(用得最多) -->
<h2>人员列表</h2>
<ul>
<li v-for="p in persons" :key="p.id">
{{p.id}}
</li>
<li v-for="(p,index) in persons" :key="index">
{{p.id}}
</li>
</ul>
<!-- 遍历对象的写法 -->
<h2>汽车信息</h2>
<li v-for="(value,key) in car" :key="key">
{{value}}--{{key}}
</li>
<!-- 遍历字符串的写法( 用得比较少) -->
<h2>测试遍历字符串</h2>
<ul>
<li v-for="(a,b) in str">
<!-- a就是每个字符,b就是每个字符的索引值 -->
{{a}}-{{b}}
</li>
</ul>
<!-- 遍历指定次数(非常少见) -->
<h2>测试遍历字符串</h2>
<ul>
<li v-for="(a,b) in 5">
<!-- a从1开始往后计数,1、2、3这样,b就是每个数字的索引值 -->
{{a}}-{{b}}
</li>
</ul>
</div>
<script>
new Vue({
el: '#vu',
data: {
persons: [
{ id: '001', name: '张三', age: '18' },
{ id: '002', name: '李四', age: '19' },
{ id: '003', name: '王五', age: '20' }
],
car: {
name: '奥迪A8',
price: '50万',
color: '黑色'
},
str: 'hello'
}
})
</script>
1.2 v-for中key的原理
先看一个小案例,以index为索引在现有的列表数据前面添加一条数据,会出现输入框与数据的错配情况
产生此问题的原因如下:
原始数据→Vue生成虚拟dom→虚拟dom转为真实dom,此时在输入框输入数据(数据残留在真实dom中)
插入新的数据→Vue根据新数据产生新的虚拟dom→新旧虚拟dom进行对比,key相同的在一起对比,在Vue看来,新、旧虚拟dom中如果有相同的部分,则新dom无需再转化为真实dom,直接把旧虚拟dom已经转好的真实dom拿过来即可,而新旧虚拟dom中的 input标签在Vue看来是一样的,直接把旧dom转化好的真实dom拿过来用即可。问题的关键就在于,新虚拟dom中插入的数据占据了key=0这个位置(因为采用的是索引值作为key),这就导致了新旧虚拟dom是不同的(key值相同的情况下)。
解决这个问题,可以在v-for的时候采用数据自身的标识(如id)来作为key。
<div id="vu">
<!-- 遍历数组的写法(用得最多) -->
<h2>人员列表</h2>
<button @click.once="add">添加一个老刘</button>
<ul>
<!-- p是person中每项的值, index是索引 -->
<li v-for="(p,index) in persons" :key="p.id">
{{p.name}} {{p.age}}--{{index}}
<input type="text">
</li>
</ul>
</div>
<script>
new Vue({
el: '#vu',
data: {
persons: [
{ id: '001', name: '张三', age: '18' },
{ id: '002', name: '李四', age: '19' },
{ id: '003', name: '王五', age: '20' }
],
},
methods: {
add() {
//定义老刘的个人信息,将其添加在persons 数组的前面
const p = { id: '004', name: '老刘', age: '60' };
this.persons.unshift(p);
}
},
})
</script>
1.3key原理的总结
面试题:react、vue中的key有什么作用?(key的内部原理)
1.虚拟DOM中key的作用:
key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,
随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
2.对比规则:
(1).旧虚拟DOM中找到了与新虚拟DOM相同的key:
①.若虚拟DOM中内容没变, 直接使用之前的真实DOM!
②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。
(2).旧虚拟DOM中未找到与新虚拟DOM相同的key创建新的真实DOM,随后渲染到到页面。
3.用index作为key可能会引发的问题:
- 若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
2. 如果结构中还包含输入类的DOM:
3. 会产生错误DOM更新 ==> 界面有问题。
- 开发中如何选择key?:
1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。
2.列表过滤
2.1搜索小案例
在输入框输入名字(单个字或者全名),列表展示筛选过的数据。
2.1.1watch方法实现
<div id="vu">
<!-- 遍历数组的写法(用得最多) -->
<h2>人员列表</h2>
<input type="text" placeholder="请输入名字" v-model="input">
<ul>
<li v-for="p in filePersons" :key="p.id">
{{p.id}}{{p.name}}
</li>
<br>
{{input}}
</ul>
</div>
<script>
new Vue({
el: '#vu',
data: {
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: '男' }
],
input: '',
filePersons: []
},
watch: {
input: {
immediate: true,
handler(val) {
this.filePersons = this.persons.filter((p) => {
return p.name.indexOf(val) != -1;
})
}
}
}
})
</script>
2.1.2computed实现
<div id="vu">
<!-- 遍历数组的写法(用得最多) -->
<h2>人员列表</h2>
<input type="text" placeholder="请输入名字" v-model="input">
<ul>
<li v-for="p in filePersons" :key="p.id">
{{p.id}}{{p.name}}
</li>
<br>
{{input}}
</ul>
</div>
<script>
new Vue({
el: '#vu',
data: {
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: '男' }
],
input: '',
},
computed: {
filePersons() {
return this.persons.filter((p) => {
return p.name.indexOf(this.input) != -1;
})
}
}
})
</script>
2.1.3 列表排序+过滤
<div id="vu">
<!-- 遍历数组的写法(用得最多) -->
<h2>人员列表</h2>
<input type="text" placeholder="请输入名字" v-model="input">
<button @click="sortType = 1">年龄升序</button>
<button @click="sortType = 2">年龄降序</button>
<button @click="sortType = 0">原始排序</button>
<ul>
<li v-for="p in filePersons" :key="p.id">
{{p.id}}{{p.name}}-{{p.age}}-{{p.sex}}
</li>
<br>
{{input}}
</ul>
</div>
<script>
new Vue({
el: '#vu',
data: {
persons: [
{ id: '001', name: '马冬梅', age: '30', sex: '女' },
{ id: '002', name: '周冬雨', age: '19', sex: '女' },
{ id: '003', name: '周杰伦', age: '36', sex: '男' },
{ id: '004', name: '温兆伦', age: '20', sex: '男' }
],
input: '',
sortType: ''
},
computed: {
filePersons() {
const arr = this.persons.filter((p) => {
return p.name.indexOf(this.input) != -1;
})
if (this.sortType) {
arr.sort((a, b) => {
return this.sortType === 1 ? a.age - b.age : b.age - a.age;
})
}
return arr;
}
}
})
</script>
\