饮水思源:https://www.bilibili.com/video/BV1Zy4y1K7SH?p=30&spm_id_from=pageDriver
一、关于key
反例
一个反例,用index作为key出bug
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title></title> <script src="JS/vue.js"></script> </head> <body> <div id="root"> <h1>{{header}}</h1> <ul> <!-- key相当于人类的身份证,保证每条数据的key不同就行 。 1 key只存在于虚拟DOM中 2 由于虚拟DOM对比算法,采用index作为key时,如果在开头 或者中间等地方插入,或者其它一些破坏顺序的操作,可能导致,例如 key=1对应数据实质上已经替换了(不是同一个人了),言下之意, 1这个身份证号对应的人突然换了一个,虚拟DOM实际上根据key=1去对 比两个不同的人来对页面进行更新(错位对比),那么不仅可能造成效率问题, 也可能导致一些出乎意料的其它问题。结论,尽量不用index做id --> <li v-for="(article, index) in articles" :key="index"> {{article.title}} --- index = {{index}} <input type="text"> </li> </ul> <button id="btnAdd">添加一篇文章</button> </div> <script> const articles = [ { id: 1, title: '这个是文章1' }, { id: 2, title: '这个是文章2' }, { id: 3, title: '这个是文章3' }, ] const vm = new Vue({ el: "#root", data: { header: "key 的原理探究 --- 一个出错的例子", articles: articles, }, }) let i = 4; document.querySelector("#btnAdd").addEventListener("click", () => { articles.unshift({ id: i, title: `这个是文章${i++}`, }) }) </script> </body>
正例
修改一下,一个正确的例子,用唯一的id作key:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title></title> <script src="JS/vue.js"></script> </head> <body> <div id="root"> <h1>{{header}}</h1> <ul> <li v-for="(article, index) in articles" :key="article.id"> {{article.title}} --- index = {{index}} <input type="text"> </li> </ul> <button id="btnAdd">添加一篇文章</button> </div> <script> const articles = [ { id: 1, title: '这个是文章1' }, { id: 2, title: '这个是文章2' }, { id: 3, title: '这个是文章3' }, ] const vm = new Vue({ el: "#root", data: { header: "key 的原理探究 --- 一个正确的例子", articles: articles, }, }) let i = 4; document.querySelector("#btnAdd").addEventListener("click", () => { articles.unshift({ id: i, title: `这个是文章${i++}`, }) }) </script> </body> </html>
二、列表过滤(监视器VS.计算属性)
效果:
监视器实现
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title></title> <script src="JS/vue.js"></script> </head> <body> <div id="root"> <input type="text" placeholder="请输入文章标题" v-model="keyWord"> <ul v-show="!searchMode"> <li v-for="(x, index) in allArticles" :key="x.id"> #{{index}}# 标题:{{x.title}} 创建时间:{{x.create_time}} </li> </ul> <ul v-show="searchMode"> <li v-for="(x, index) in filArticles" :key="x.id"> #{{index}}# 标题:{{x.title}} 创建时间:{{x.create_time}} </li> </ul> </div> <script> const articles = [ { id: 1, title: '文章123', create_time: '2022-01-22', }, { id: 2, title: '文章345', create_time: '2022-01-27', }, { id: 3, title: '文章567', create_time: '2022-01-11', }, { id: 4, title: '文章6789', create_time: '2022-01-05', }, ] const vm = new Vue({ el: "#root", data: { allArticles: articles, keyWord: "", searchMode: false, filArticles: [], }, watch: { keyWord(newVal) { if (newVal === "") { this.searchMode = false; } else { this.searchMode = true; this.filArticles = this.allArticles.filter(x => { return x.title.indexOf(newVal) !== -1; }) } }, } }) </script> </body> </html>
计算属性实现
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title></title> <script src="JS/vue.js"></script> </head> <body> <div id="root"> <input type="text" placeholder="请输入文章标题" v-model="keyWord"> <ul v-show="!searchMode"> <li v-for="(x, index) in allArticles" :key="x.id"> #{{index}}# 标题:{{x.title}} 创建时间:{{x.create_time}} </li> </ul> <ul v-show="searchMode"> <li v-for="(x, index) in filArticles" :key="x.id"> #{{index}}# 标题:{{x.title}} 创建时间:{{x.create_time}} </li> </ul> </div> <script> const articles = [ { id: 1, title: '文章123', create_time: '2022-01-22', }, { id: 2, title: '文章345', create_time: '2022-01-27', }, { id: 3, title: '文章567', create_time: '2022-01-11', }, { id: 4, title: '文章6789', create_time: '2022-01-05', }, ] const vm = new Vue({ el: "#root", data: { allArticles: articles, keyWord: "", }, computed: { searchMode() { return this.keyWord !== ""; }, filArticles() { return this.allArticles.filter(x => { return x.title.indexOf(this.keyWord) !== -1; }) } } }) </script> </body> </html>
三、列表排序
效果:
实现:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title></title> <script src="JS/vue.js"></script> </head> <body> <div id="root"> <input type="text" placeholder="请输入文章标题" v-model="keyWord"> <button v-on:click="sortByTime">按时间排序</button> <button v-on:click="sortByDefault">原顺序</button> <ul> <li v-for="(article, index) in filArticles" :key="article.id"> #{{index}}# {{article.title}} 创建时间{{article.create_time}} </li> </ul> </div> <script> const allArticles = [ { id: 1, title: '章123', create_time: '2022-01-22', }, { id: 2, title: '文章345', create_time: '2022-01-27', }, { id: 3, title: '章567', create_time: '2022-01-11', }, { id: 4, title: '文章6789', create_time: '2022-01-05', }, { id: 5, title: '文章6789', create_time: '2022-01-01', }, ] const vm = new Vue({ el: "#root", data: { keyWord: "", sortType: 0, // 0 原顺序 1 按时间排序 }, computed: { filArticles() { let tmpArr = allArticles.filter(article => { return article.title.indexOf(this.keyWord) !== -1; }) if (this.sortType) { tmpArr.sort((a, b) => { return a.create_time > b.create_time ? 1 : -1 }) } return tmpArr } }, methods: { sortByTime() { this.sortType = 1; }, sortByDefault() { this.sortType = 0; }, }, }) </script> </body> </html>