vlambda博客
学习文章列表

vue列表渲染、key作用与原理、列表过滤排序

一、列表渲染

v-for指令:用于遍历数据

语法:

v-for="(item, index) in xxx" :key="yyy"// 可以用of替代in作为分隔符v-for="item of items"

示例:其中items是源数据数组,item是被迭代的数组元素的别名

<ul>  <li v-for="(item,index) in items" :key="item.id">   {{item.message}}  </li></ul>var vm = new Vue({ el: '#app', data: { items: [ { id:1, message: 'Foo' }, { id:2, message: 'Bar' } ] }})

可遍历数组、对象、字符串(用的少)、指定次数(用的少)

1、遍历数组

<ul> <li v-for="(item,index) in items" :key="item.id"> {{item.message}} </li></ul>var vm = new Vue({ el: '#app', data: { items: [ { id:1, message: 'Foo' }, { id:2, message: 'Bar' } ] }})

2、遍历对象,在遍历对象时,会按Object.keys()的结果遍历,但不能保证它的结果在不同的JavaScript引擎下都一致。

<ul> <li v-for="(val,key,index) in person" :key="key"> {{val}}--{{key}}--{{index}} </li></ul>var vm = new Vue({ el:"#app", data:{    person:{ id:1, name:"张三", age:20 } }})// 输出结果如下:1--id--0张三--name--120--age--2

3、遍历字符串(用得少)

<ul> <li v-for="(chart,index) in str" :key="index"> {{chart}}--{{index}} </li></ul>var vm = new Vue({ el:"#app", data:{ str:"hello" }})// 输出结果如下:h--0e--1l--2l--3o--4

4、遍历指定次数(用得少)

<ul> <li v-for="(number,index) in 5" :key="index"> {{number}}--{{index}} </li></ul>var vm = new Vue({ el:"#app", data:{}})// 输出结果如下:1--02--13--24--35--4




二、key作用与原理

给节点做个标识,相当于人类的身份证号

1、虚拟DOM中key的作用:

key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较

2、对比规则:

旧虚拟DOM中找到了与新虚拟DOM相同的key:

  • 若虚拟DOM中内容没有变化,直接使用之前的真实DOM

  • 若虚拟DOM中内容变了,则生成新的真实DOM,随后替换页面中之前的真实DOM

旧虚拟DOM中未找到与新虚拟DOM相同的key:创建新的真实DOM,随后渲染到页面

3、用index作为key可能会引起的问题:

  • 若对数据进行:逆序添加、逆序删除等破坏顺序操作:

        会产生没有必要的真实DOM更新=》界面效果没问题,但效率低(因为需要重新渲染

  • 如果结构中还包含输入类的DOM:

        会产生错误DOM更新=》界面有问题

4、开发中如何选择key

  • 最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值。

  • 如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表展示,使用index作为key没有问题。

示例:遍历列表以index作为key

如下图:根据初始数据生成虚拟DOM,此时这些虚拟DOM存储在内存中,然后将虚拟DOM转为真实DOM,用户在真实DOM中输入内容,新的数据出现了,老刘,被放到第一个数组中,根据新数据生成新虚拟DOM,虚拟DOM对比算法

遍历列表以id作为key




三、列表过滤

实现前端数据搜索功能

<div id="app"> <input type="text" v-model="keyWorld" /> <ul> <li v-for="p in filterPersons" :key="p.id"> {{p.name}}--{{p.age}}--{{p.sex}} </li> </ul></div>

1、使用watch


<script> Vue.config.productionTip = false; new Vue({ el: "#app", data: { keyWorld: "", persons: [ { id: 1, name: "马冬梅", sex: "女", age: 18, }, { id: 2, name: "周冬雨", sex: "女", age: 19, }, { id: 3, name: "周杰伦", sex: "男", age: 20, }, { id: 4, name: "林俊杰", sex: "男", age: 21, }, ], filterPersons: [], }, watch: { keyWorld: { immediate: true, handler() { this.filterPersons = this.persons.filter((item) => { return item.name.indexOf(this.keyWorld) > -1; }); }, },    }, });</script>

使用计算属性

<script> Vue.config.productionTip = false; new Vue({ el: "#app", data: { keyWorld: "", persons: [ { id: 1, name: "马冬梅", sex: "女", age: 18, }, { id: 2, name: "周冬雨", sex: "女", age: 19, }, { id: 3, name: "周杰伦", sex: "男", age: 20, }, { id: 4, name: "林俊杰", sex: "男", age: 21, },      ], }, computed: { filterPersons() { return this.persons.filter((item) => { return item.name.indexOf(this.keyWorld) > -1; }); },    }, });</script>

3、使用方法

<div id="app">  <input type="text" v-model="keyWorld" @input="keyChange" /> <ul> <li v-for="p in filterPersons" :key="p.id"> {{p.name}}--{{p.age}}--{{p.sex}} </li> </ul></div><script> Vue.config.productionTip = false; new Vue({ el: "#app", data: { keyWorld: "", persons: [ { id: 1, name: "马冬梅", sex: "女", age: 18, }, { id: 2, name: "周冬雨", sex: "女", age: 19, }, { id: 3, name: "周杰伦", sex: "男", age: 20, }, { id: 4, name: "林俊杰", sex: "男", age: 21, }, ], filterPersons: [],    }, created() { this.keyChange(); }, methods: { keyChange() { this.filterPersons = this.persons.filter((item) => { return item.name.indexOf(this.keyWorld) > -1; }); }, }, });</script>




四、列表排序

实现前端数据搜索和排序功能

<div id="app"> <input type="text" v-model="keyWorld" /> <button @click="sortType=2">升序</button> <button @click="sortType=1">降序</button> <button @click="sortType=0">原顺序</button> <ul> <li v-for="p in filterPersons" :key="p.id"> {{p.name}}--{{p.age}}--{{p.sex}} </li> </ul></div>

JS部分

<script> Vue.config.productionTip = false; new Vue({ el: "#app", data: { sortType: 0, keyWorld: "", persons: [ { id: 1, name: "马冬梅", sex: "女", age: 32, }, { id: 2, name: "周冬雨", sex: "女", age: 19, }, { id: 3, name: "周杰伦", sex: "男", age: 25, }, { id: 4, name: "林俊杰", sex: "男", age: 16, }, ], }, computed: { filterPersons() { var arr = this.persons.filter((item) => { return item.name.indexOf(this.keyWorld) > -1; }); if (this.sortType) { arr.sort((p1, p2) => { return this.sortType == 1 ? p2.age - p1.age : p1.age - p2.age; }); } return arr; }, }, });</script>