列表渲染:进阶
:key="index",key唯一,专门给节点一个标识,无法重复,否则报错
虚拟DOM对比算法:将初始虚拟DOM和新虚拟DOM进行对比
流程:首先来到新的虚拟DOM处,取出新的虚拟DOM的key,随后来到初始的虚拟DOM处,来找和新虚拟DOM一样key的数据
初始虚拟DOM(部分):
<li key="0">张三-18<input type='text'><li>
<li key="1">李四-19<input type='text'><li>新虚拟DOM(部分),添加一条数据:
<li key="0">老李-30<input type='text'><li>
<li key="1">张三-18<input type='text'><li>
<li key="2">李四-19<input type='text'><li>旧:张三-18
新:老李-30
这一段不同,而后面的<input type='text'>是相同的
总而言之:
对比相同的部分:复用到新的真实DOM上
对比不同的部分:旧的无法复用,只能将新的虚拟DOM中的东西转为一个新的DOM节点,那么就会出现以下情况:
前面的变为老李-30,但是后面的输入框中的内容不变,没有跟随张三-18那一行
总的来说:新的DOM中,老李-30,张三-18,李四-19都是新生成的,老李30,张三18的输入框是复用而来的
李四19的输入框是新生成的
而是用key进行唯一标识,得到的key会逐行检查是否存在对应的标识,如果没有,则全盘进行从新生成,不会只生成半边复用半边的情况
如果有,则直接复用旧的虚拟DOM中的内容并牵引到新的DOM中
还有一种情况就是没有写key,这种情况下,Vue会自动用循环索引补齐key,那就和自己确定index一样了
当index作为key

当id作为key

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>你好啊!</title>
<script type="text/javascript" src="../JS/vue.js"></script>
</head>
<body>
<div id="root">
<button @click.once="add">添加一个老刘</button>
<ul>
<!--
key是vue内部在使用,我们不能使用
-->
<!--
这种写法有问题,在完成输入框输入之后再按按钮,会发现错乱问题
index是循环的索引
<li v-for="(p,index) in personList" :key="index">
{{p.name}}-{{p.age}}
<input type="text">
</li>
-->
<!-- -->
<li v-for="p in personList" :key="p.id">
{{p.name}}-{{p.age}}
<input type="text">
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
new Vue({
el: "#root",
data: {
personList:[
{ id: '001', name: '张三', age: 18 },
{ id: '002', name: '老李', age: 19 },
{ id: '003', name: '王五', age: 20 },
],
},
methods: {
add(){
const p = {
id: '004',
name: '老刘',
age: 40
}
this.personList.unshift(p)
}
},
})
</script>
</body>
</html>总结:
react,vue的key有什么作用(key的内部原理)
1,虚拟DOM中key的作用:
key是虚拟DOM对象的标识,当状态中的数据发生变化时,Vue会根据[新数据]生成[新的虚拟DOM]
随后Vue进行[新虚拟DOM],[旧虚拟DOM]的差异比较,比较规则如下:
2,对比规则:
旧虚拟DOM中找到了和新虚拟DOM相同的key:
若虚拟DOM中内容不变,直接使用之前的真实DOM
若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
3,用index作为key可能会引发的问题:
1,若对数据进行:逆序添加,逆序删除等破坏顺序的操作:
会产生没有必要的真实DOM更新==>界面效果没有问题,但是效率低下
2,如果数据中还包含输入类的DOM:
会产生错误DOM更新===>界面有问题
4,开发中如何选择key:
1,最好使用每条数据的唯一标识作为key,比如id,手机号,身份证号等唯一值
2,如果不存在对数据的逆序添加,逆序删除等破坏顺序的操作,仅用于渲染列表用于展示,使用index作为key是没有问题的
列表过滤
对一个字符串使用indexOf(),用来查询是否存在
const str='abc'
str.indexOf('x') 此时得到的值为-1,因为没有找到x这个字符
如果包含要搜寻的字符,那么它就会返回这个字符的位置,
str.indexOf('a') 得到的值为0
注意:str.indexOf('') 空字符串,得到的是0而非-1
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>你好啊!</title>
<script type="text/javascript" src="../JS/vue.js"></script>
</head>
<body>
<div id="root">
<h2>人员列表</h2>
<!-- 模糊搜索 -->
<input type="text" placeholder="请输入姓名" v-model="keyWord">
<ul>
<li v-for="p in filPersonList" :key="p.id">
{{p.name}}-{{p.age}}-{{p.sex}}
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
// #region
// const vm = new Vue({
// el: "#root",
// data: {
// keyWord:'',
// personList:[
// { id: '001', name: '马冬梅', age: 19, sex: '女' },
// { id: '002', name: '周冬雨', age: 20, sex: '女' },
// { id: '003', name: '周杰伦', age: 21, sex: '男' },
// { id: '004', name: '温兆伦', age: 22, sex: '男' },
// ],
// filPersonList:[],
// },
// watch:{
// keyWord:{
// immediate:true,
// handler(newValue, oldValue) {
// console.log('keyWord被修改', newValue)
// // 通过filter会得到一个新的数组,需要其将旧数组覆盖,但这样也有坏处,过滤掉的数组成员将不再回来
// // 也就是彻底丢失了,到后面越搜索越少,注意,不要随便修改personList这个数组
// this.filPersonList = this.personList.filter((p) => {
// return p.name.indexOf(newValue) !== -1
// })//根据条件将符合的数据过滤出来
// }
// }
// },
// })
// #endregion
// 使用computed实现
const vm = new Vue({
el: "#root",
data: {
keyWord:'',
personList:[
{ 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:{
filPersonList(){
return this.personList.filter((p) => {
return p.name.indexOf(this.keyWord) !== -1
})
}
}
})
</script>
</body>
</html>列表排序
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>你好啊!</title>
<script type="text/javascript" src="../JS/vue.js"></script>
</head>
<body>
<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 in filPersonList" :key="p.id">
{{p.name}}-{{p.age}}-{{p.sex}}
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
// 使用computed实现
const vm = new Vue({
el: "#root",
data: {
keyWord:'',
sortType:0,//0代表原顺序,1代表降序,2代表升序
personList:[
{ id: '001', name: '马冬梅', age: 25, sex: '女' },
{ id: '002', name: '周冬雨', age: 24, sex: '女' },
{ id: '003', name: '周杰伦', age: 33, sex: '男' },
{ id: '004', name: '温兆伦', age: 30, sex: '男' },
],
},
computed:{
filPersonList(){
const arr = this.personList.filter((p) => {
return p.name.indexOf(this.keyWord) !== -1
})
//判断是否需要排序
if(this.sortType!==0){
arr.sort((p1,p2)=>{
return this.sortType===1?p2.age-p1.age:p1.age-p2.age
})
// sort可以改变原数组,谁.sort就是对谁排序,数组本身会发生改变
}
return arr
}
}
})
// let arr = [1,5,3,6,8,2]
// arr.sort((a,b)=>{
// return a-b;//此为升序排序
// // return b-a;//此为降序排序
// })
// console.log(arr)
</script>
</body>
</html>