Vue2 - 23-03-20

First Post:

Last Update:

Vue2 - 23-03-20

key的作用与原理

  • 如果使用的是生成的索引作为key,破坏key与index的顺序之后,虚拟dom会根据diff算法(对比算法),保留原有key上面的东西,造成顺序混乱
  • key为p.id的时候,会根据唯一标识ID进行对比
  • 没有书键入key的时候默认会生成index为key


如果数据是从后方插入的时候就不会出现下面问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>key的原理</title>
<script src="../resources/js/vue.js"></script>
</head>
<body>
<div id="root">
<h2>测试数组遍历</h2>
<button @click="add">添加一个老刘</button>
<ul>
<li v-for="(p,index) in personList" :key="index">
{{p.name}}-{{p.age}}
<input type="text">
</li>
</ul>
<ul>
<li v-for="(p,index) 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>

列表过滤及排序

  • 过滤
    list.filter((listItem)=>{ return listItem.indexOf(keyword) !== -1 })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>列表过滤</title>
<script src="../resources/js/vue.js"></script>
</head>
<body>
<div id="root">
<h2>人员遍历</h2>
<input type="text" placeholder="请输入名字" v-model="keyword">
<ul>
<li v-for="(p,index) in filPersonList" :key="index">
{{p.name}}-{{p.age}}--{{p.gender}}
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
//同watch实现
//#region
/*
new Vue({
el: '#root',
data:{
personList:[
{id:'001',name:'马冬梅',age:18,gender:'女'},
{id:'002',name:'周冬雨',age:19,gender:'女'},
{id:'003',name:'周杰伦',age:20,gender:'男'},
{id:'004',name:'温兆伦',age:21,gender:'男'}
],
keyword:'',
filPersonList:[]
},
watch:{
keyword:{
handler(val){
this.filPersonList = this.personList.filter((p)=>{
return p.name.indexOf(val) !=-1
})
},
immediate:true
}
}
})*/
//#endregion
//用computed实现
new Vue({
el: '#root',
data:{
personList:[
{id:'001',name:'马冬梅',age:18,gender:'女'},
{id:'002',name:'周冬雨',age:19,gender:'女'},
{id:'003',name:'周杰伦',age:20,gender:'男'},
{id:'004',name:'温兆伦',age:21,gender:'男'}
],
keyword:'',

},
computed:{
filPersonList(){
return this.personList.filter((p)=>{
return p.name.indexOf(this.keyword) !== -1
})
}
}
})
</script>
</body>
</html>
  • 排序
    升序: const arr = [1,5,3];arr.sort((a,b)=>{ return a-b }) =>[1, 3, 5]
    降序: const arr = [1,5,3];arr.sort((a,b)=>{ return a-b }) =>[5, 3, 1]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>列表过滤后排序</title>
<script src="../resources/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,index) in filPersonList" :key="p.id">
{{p.name}}-{{p.age}}--{{p.gender}}
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
//用computed实现
new Vue({
el: '#root',
data:{
personList:[
{id:'001',name:'马冬梅',age:30,gender:'女'},
{id:'002',name:'周冬雨',age:27,gender:'女'},
{id:'003',name:'周杰伦',age:20,gender:'男'},
{id:'004',name:'温兆伦',age:21,gender:'男'}
],
keyword:'',
sortType:0,//0:原顺序,1:降序,2:升序
},
computed:{
filPersonList(){
const arr = this.personList.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>
</body>
</html>

Vue监测(侦听)数据的原理

更新时候出现的一个问题

点击按钮之后,开发者工具中没有发现变化,列表也没变
Vue中数组没有getter、setter,只能通过七个变更方法才能做到响应式

Vue对被侦听的数组变更方法进行了包裹

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>更新时出现的一个问题</title>
<script src="../resources/js/vue.js"></script>
</head>
<body>
<div id="root">
<h2>人员遍历</h2>
<button @click="updateMei">更新马冬梅的信息</button>
<ul>
<li v-for="(p,index) in personList" :key="p.id">
{{p.name}}-{{p.age}}--{{p.gender}}
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
//用computed实现
new Vue({
el: '#root',
data:{
personList:[
{id:'001',name:'马冬梅',age:30,gender:'女'},
{id:'002',name:'周冬雨',age:27,gender:'女'},
{id:'003',name:'周杰伦',age:20,gender:'男'},
{id:'004',name:'温兆伦',age:21,gender:'男'}
],
},
methods:{
updateMei(){
// this.personList[0].name='马老师';
// this.personList[0].age=50;
// this.personList[0].gender='男';
// X this.personList[0] = {id:'001',name:'马老师',age:50,gender:'男'};
this.personList.splice(0,1,'打台球')
}
}
})
</script>
</body>
</html>

模拟监测的实现

为了响应式,Vue实例将data的东西交给Observer进行处理,然后再给了一份vm._data,一份data

这里模拟了加工的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>模拟一个数据监测</title>
</head>
<body>
<div id="root">
<h2>学校名称:{{}}</h2>
<h2>学校地址:{{}}</h2>
</div>
<script type="text/javascript">
let data = {
name:"gdip",
address:"nanhai",
};
const obs = new Observer(data);
const vm = {}
vm._data = data = obs;
//Vue实例将data的东西交给Observer进行处理,然后再给了一份vm._data,一份data
function Observer(val) {
//获取所有的key
const keys = Object.keys(val);
keys.forEach((key) => {
Object.defineProperty(this,key,{//this指的是Object本身
get() {
return val[key];
},
set(proVal) {
console.log("监测到了修改,Vue去更新页面");
val[key] = proKey;
}
})
});
}
</script>
</body>
</html>

数据在Vue实例通过Observer进行的对data处理之后会同时赋值给data、vm._data
getter、setter是为了响应式而生;
数据代理中我认为代理商就是getter和setter,vm的属性来自他们而不是直接读取从vue实例拷贝过来的_data;

Vue.set,添加一个响应式属性

只能给data里面的某一个对象追加属性,不能是直接给vm(vue实例的data)追加
X没有响应式:vm._data.student.gender = ‘男’
详见文档->Vue.set
Vue.set( target, propertyName/index, value )

  • Vue.set(this.student,'gender','男')
  • this.$set(this.student,'gender','男')

演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue监测数据改变的原理</title>
<script src="../resources/js/vue.js"></script>
</head>
<body>
<div id="root">
<h1>学校信息:</h1>
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
<hr>
<h1>学生信息:</h1>
<button @click="addGender">添加一个性别属性</button>
<h2 v-if="student.gender">学生性别:{{student.gender}}</h2>
<h2>学生姓名:{{student.name}}</h2>
<h2>学生年龄:真实{{student.age.rAge}},对外{{student.age.sAge}}</h2>
<h2>朋友们</h2>
<ul>
<li v-for="(friend, index) in student.friends" :key="index">
{{friend.name}}--{{friend.age}}
</li>
</ul>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
new Vue({
el: '#root',
data:{
name:"gdip",
address:"nanhai",
student:{
name:'Tom',
age:{
rAge:40,
sAge:29
},
friends:[
{name:'jerry',age:17},
{name:'tony',age:30}
]
}
},
methods:{
addGender(){
// Vue.set(this.student,'gender','男')
this.$set(this.student,'gender','男')
}
}
})
</script>
</body>
</html>

Vue监测数据改变的原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue监测数据改变的原理</title>
<script src="../resources/js/vue.js"></script>
</head>
<body>
<div id="root">
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
</div>
<script type="text/javascript">
Vue.config.productionTip = false;
//用computed实现
const vm = new Vue({
el: '#root',
data:{
name:"gdip",
address:"nanhai",
student:{
name:'Tom',
age:{
rAge:40,
sAge:29
}
},
friends:[
{name:'jerry',age:17}
]
},
methods:{
updateMei(){
// this.personList[0].name='马老师';
// this.personList[0].age=50;
// this.personList[0].gender='男';
this.personList[0] = {id:'001',name:'马老师',age:50,gender:'男'};
}
}
})
</script>
</body>
</html>