官网的介绍
image-20230821000956765
索引
可以通过第二个参数获得索引值
<div v-for="(item, index) in list"></div>
上面的key也可以根据索引来定义
<div v-for="(item, index) in list"></div>
这里可能会有问题,能用index作为key吗?也可以,但是不推荐!
比如下面案例
<li v-for="(item, index) in list" :key="index"> {{ item }} </li>
使用 index 作为 key 存在以下问题:
- 列表重新排序时,元素的 key 会变化,导致状态混乱(比如新添加一个索引为0索引的小索奇,它就替代了初始索引为0的张三,与原来进行对比,发现张三被小索奇怼跑了,这不闹的吗?)
- 不能准确判断变化的原因是索引变还是数据变
- 删除元素时,产生的新索引不会跟踪到原元素
正确写法,还是建议绑定到item.id
身上,使用每一项数据中稳定且唯一的标识作为 key!
注意以面试题形式存在
image-20230821002410628
拓展Diff算法
key是虚拟DOM对象的标识,当数据变化时,Vue就会根据新数据生成新的虚拟DOM
diff 算法是 Vue 和 React 等虚拟 DOM 框架实现高效 DOM 更新的关键算法它可以增量更新视图,避免重新渲染整个 DOM 树
diff算法的基本原理是:
- 将当前虚拟 DOM 和上一次虚拟 DOM 进行对比,找出变化的内容(没有变化的直接就复用了)
- 如果在旧虚拟节点中未找到与新虚拟节点相同的key,那么直接创建新的虚拟DOM,进行渲染,如果key同,那么就对比内容
- 不直接操作 DOM,而是将变化记录到一个JS 对象中
- 将这些变化一次性更新到实际的 DOM树上
简单示例
diff算法对比会发现,只需要将 B 换成 C 即可,无需重新渲染整个 UL这样避免了不必要的 DOM 操作
<!-- 上次虚拟DOM --> <ul> <li>A</li> <li>B</li> </ul> <!-- 当前虚拟DOM --> <ul> <li>A</li> <li>C</li> </ul>
Vue 和 React 都使用类似的 diff 算法实现最小化更新实际 DOM 的目的,这带来非常高的性能优势
image-20230821005540298
数组更新检测
Vue包含一系列观察数组变异方法来响应式更新视图
像push、pop、splice等方法
列表过滤
用两组代码分别实现过滤效果
watch实现
new Vue({ el:'#root', data:{ keyWord:'', persons:[ {id:'001',name:'马冬梅、',age:19,sex:'女'}, {id:'002',name:'周冬雨',age:20,sex:'女'}, {id:'003',name:'周杰伦',age:21,sex:'男'}, {id:'004',name:'温兆伦',age:22,sex:'男'} ], //存放过滤后的新数组 filPerons:[] }, watch:{ keyWord:{ immediate:true, handler(val){ this.filPerons = this.persons.filter((p)=>{ // 返回一个布尔值 return p.name.indexOf(val) !== -1 }) } } } })
computed实现
new Vue({ el:'#root', data:{ keyWord:'', persons:[ {id:'001',name:'马冬梅',age:19,sex:'女'}, {id:'002',name:'周冬雨',age:20,sex:'女'}, {id:'003',name:'周杰伦',age:21,sex:'男'}, {id:'004',name:'温兆伦',age:22,sex:'男'} ] }, computed:{ filPerons(){ // 计算属性必备return return this.persons.filter((p)=>{ // 返回一个布尔值,计算属性没有newValue属性,但可以通过用户输入的值来拿 return p.name.indexOf(this.keyWord) !== -1 }) } } })
初始时计算属性会默认调用get,当依赖的数据变化时,计算属性也会自动调用~从而实现过滤
当computed和watch都能实现时,优先考虑computed
拓展filter
filter方法的作用是:
- 它接收一个函数作为参数,这个函数会逐个处理数组中的每个元素
- 函数返回一个布尔值,true表示保留该元素,false表示过滤掉该元素
- filter会返回一个新数组,包含执行函数返回true的元素
- 下面示例中的name代表callback函数的参数,表示当前正在遍历到的数组元素
const names = ['王美丽', '李小福', '张快乐', '赵细腻', '吉祥如意', '康健壮']; const longNames = names.filter(name => name.length > 3); const loudLongNames = longNames.map(name => name.toUpperCase()); console.log(loudLongNames); // 输出:['李小福', '张快乐', '赵细腻', '吉祥如意']
这里我们过滤出了长度大于3个字的中文名字,然后把它们转换成大写,这里仅仅为了多用一个方法~
filter 最典型的用途就是过滤数组,接受判断条件并返回过滤后的新数组,
列表排序
案例:实现过滤+排序
<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) of filPerons" :key="p.id"> {{p.name}}-{{p.age}}-{{p.sex}} <input type="text"> </li> </ul> </div> <script type="text/JS"> Vue.config.productionTip = false new Vue({ el:'#root', data:{ keyWord:'', sortType:0, //0原顺序 1降序 2升序 persons:[ {id:'001',name:'马冬梅',age:30,sex:'女'}, {id:'002',name:'周冬雨',age:31,sex:'女'}, {id:'003',name:'周杰伦',age:18,sex:'男'}, {id:'004',name:'温兆伦',age:19,sex:'男'} ] }, computed:{ filPerons(){ 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>
image.png
拓展
Arrays.sort()
const months = ['March', 'Jan', 'Feb', 'Dec']; months.sort(); console.log(months); // output: Array ["Dec", "Feb", "Jan", "March"] const array1 = [1, 30, 4, 21, 100000]; array1.sort(); console.log(array1); // output: Array [1, 100000, 21, 30, 4]
如果提供了 比较函数compareFn
,所有非 undefined
的数组元素都会按照比较函数的返回值进行排序,所有的 undefined
元素都会被排序到数组的末尾,并且不调用 compareFn
image-20230822221418048
简单案例
let arr = [66,99,88] arr.sort((a,b)=>{ // 前-后就是升序,相反则降序 return a-b }) console.log(arr) // [66, 88, 99]
如果对你有用,请点个免费的爱心叭~