02-响应式原理与事件绑定
码路教育 6/3/2022
# 1, 响应式数据(属性)原理?
- 面试必问
- 响应式数据【属性】: 在配置项data当中定义的属性,都是响应式数据,作为VM对象的响应式属性
- 所谓的响应式是指数据变化,视图跟着变化
Vue2版本响应式数据实现原理
- Vue框架中VM对象的响应式数据实现原理,利用的是Object.defineProperty实现的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 引入Vue.js,人家向外暴露一个Vue类 new Vue -->
<script src="../lib/vue2.7.8.js"></script>
</head>
<body>
<!-- 定义的容器 -->
<div id="app">
</div>
<script>
// 问:下面的代码中有几个对象?
// 答: 3个 vm叫实例对象 {}配置对象 data中返回一个对象
let vm = new Vue({
el:"#app",
data(){
return {
msg:"hello vue"
}
}
});
// msg会挂载到vm实例上,作为vm的属性
console.log(vm);
// 在vm实例上,还有一个叫_data属性,它里面也包含了data中的数据
// 之所以以_打头,表示不希望别人使用
console.log(vm._data);
// vm这个对对象 与 data函数调用返回的对象 是两个不同的对象
console.log(vm.msg === vm._data.msg);
</script>
</body>
</html>
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
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 引入Vue.js,人家向外暴露一个Vue类 new Vue -->
<script src="../lib/vue2.7.8.js"></script>
</head>
<body>
<!-- 定义的容器 -->
<div id="app">
</div>
<script>
// vue2的响应式原理,靠之前的JS高级中的 Object.defineProperty
let vm = {};
let data = {};
// 精细化设置属性 就是给data对象添加msg属性
Object.defineProperty(data,"msg",{
// 当获取属性时,自动走get,得到的值是,return后面的值
get(){
return vm.msg;
},
// 当给msg属性设置一个属性时,会走set,设置的新值会作为set的参数
set(val){
vm.msg = val;
// 更新视图.....
}
})
// 数据变了,我要更新视图,也就是说,数据变了,我肯定要知道
// 当数据发生了变化,会走set,在set中可以更新视图...
data.msg = "i love vue"
console.log(data.msg);
</script>
</body>
</html>
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
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
# 2, 事件绑定
# 2.1, 事件的绑定
- 通过v-on指令来绑定事件,可以简写成 @事件名字,一般用简写的方式,用@替换。
- 一个元素可以同时绑定多个事件,但是一般情况下只是绑定一个
- VM对象方法的this问题, 方法不能书写箭头函数(箭头函数没有任何意义, 因为获取不到VM,获取不到响应式数据,获取到的是windows)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 引入Vue.js,人家向外暴露一个Vue类 new Vue -->
<script src="../lib/vue2.7.8.js"></script>
<style>
.box{
width: 200px;
height: 200px;
background-color: gold;
}
</style>
</head>
<body>
<!-- 定义的容器 -->
<div id="app">
<h1>{{ msg }}</h1>
<!--
指令:说白了,就是标签的自定义属性 是以v-打头
在vue中,通过指令来绑定事件
v-on:click="handle" 给div绑定点击事件 click是点击事件
v-on:事件名字 click mouseenter mouseout keyup....
v-on:事件名字 = "事件处理函数(监听器)"
-->
<!-- <div class="box" v-on:click="handle"></div> -->
<!-- v-on基本上不用,一般都使用简写 是@ -->
<div class="box" @click="handle" @mouseover="over"></div>
<!-- <button v-on:click="handle2">我是一个Button</button> -->
<button @click="handle2">我是一个Button</button>
</div>
<script>
let vm = new Vue({
el:"#app",
data(){
return {
msg:"hello vue"
}
},
// methods中放模板中绑定的监听器
// methods 加了s
// 下面的两个监听器,能不能挂载到vm实例上?
methods:{
// handle(){
// // console.log("handle...");
// // this表示vm实例
// // console.log(this.msg);
// // msg是响应式数据,数据变了,界面要更新
// this.msg = "hi vue"
// }
// methods中的方法,不要写成箭头函数的形式
// 是箭头函数,内部的this表示window
// handle: ()=>{
// console.log(this);
// this.msg = "hi vue"
// }
handle:function(){
console.log(this);
this.msg = "hi vue"
},
handle2(){
console.log("点击了按钮~");
},
over(){
console.log("鼠标移入了~");
}
}
});
// 也在methos中的方法,也会挂载到vm实例上的
vm.handle2()
</script>
</body>
</html>
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
73
74
75
76
77
78
79
80
81
82
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
73
74
75
76
77
78
79
80
81
82
# 2.2, 传参
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 引入Vue.js,人家向外暴露一个Vue类 new Vue -->
<script src="../lib/vue2.7.8.js"></script>
</head>
<body>
<!-- 定义的容器 -->
<div id="app">
<!-- 在绑定一个监听器时,()可以加也可以不加,加()的目的是为了传参 -->
<!-- " getMsg() " 这一行代码在你眼中并不是一个值 -->
<button @click=" getMsg(123) ">传递一个参数</button>
<!-- @click=后面是跟了一个"" 千万不要当成字符串,它仅仅是vue中的语法 -->
<!-- "" 仅仅是vue的语法,在""放JS表达式 -->
<button @click=" getMsg2(123,'i love you') ">传递二个参数</button>
<!-- 没有加() 在监听器中,默认第一个参数,就是事件对象 -->
<button @click=" getMsg3 ">获取事件对象方式一</button>
<!-- 加()的目的是为了传参 -->
<!-- 如果添加了(),监听器中的第1个参数,就不是事件对象了 -->
<!-- 如果还想获取事件对象,那么需要手动的传递事件对象 $event -->
<!-- 事件对象:阻止默认事件,阻止冒泡,鼠标位置,键盘码.... -->
<button @click=" getMsg4($event) ">获取事件对象方式二</button>
</div>
<script>
let vm = new Vue({
el: "#app",
// data中放响应式数据
data() {
return {
// 也就是说,可以把监听器写在data中,
// 不要写在这里,不要写在这里
getMsg4(e) {
console.log(e);
}
}
},
// methods中方法
methods: {
getMsg(a) {
console.log(a);
// console.log("getMsg...");
},
getMsg2(a, b) {
console.log(a, b);
},
getMsg3(e) {
console.log(e);
},
// getMsg4(e){
// console.log(e);
// }
}
});
</script>
</body>
</html>
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
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
# 2.3, 事件修饰符
修饰符:
- .stop - 调用 event.stopPropagation()。
- .prevent - 调用 event.preventDefault()。
- .capture - 添加事件侦听器时使用 capture 模式。
- .self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。
- .{keyAlias} - 仅当事件是从特定键触发时才触发回调。
- .once - 只触发一次回调。
- .left - 只当点击鼠标左键时触发。
- .right - 只当点击鼠标右键时触发。
- .middle - 只当点击鼠标中键时触发。
- .passive - { passive: true } 模式添加侦听器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 引入Vue.js,人家向外暴露一个Vue类 new Vue -->
<script src="../lib/vue2.7.8.js"></script>
<style>
.box{
width: 200px;
height: 200px;
background-color: skyblue;
}
</style>
</head>
<body>
<!-- 定义的容器 -->
<div id="app">
<!-- form表单有默认的提交事件 -->
<!-- a标签也有默认事件 -->
<form action="http://www.baidu.com">
<!-- <input type="submit" value="登录"> -->
<!-- @click.prevent 阻止默认事件 -->
<button @click.prevent="showMsg">点我</button>
</form>
<hr>
<div class="box" @click="showMsg2">
<button @click.stop="showMsg3">阻止冒泡</button>
</div>
<hr>
<!--
once表示只处罚一次,用的不多
-->
<button @click.once="showMsg4">只触发一次</button>
<!--
事件的修饰符可以链式来写,谁先谁后无所谓,了解:
@click.stop.prevent.once
@click.once.stop.prevent
-->
</div>
<script>
let vm = new Vue({
el:"#app",
data(){
return {
}
},
methods:{
showMsg(e){
console.log("showMsg....");
// e.preventDefault(); // 阻止默认事件
},
showMsg2(e){
console.log("showMsg2...");
},
showMsg3(e){
console.log("showMsg3...");
// e.stopPropagation()
},
showMsg4(){
console.log("showMsg4...");
}
}
});
</script>
</body>
</html>
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
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
# 2.3, 与表单元素一起使用的修饰符
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 引入Vue.js,人家向外暴露一个Vue类 new Vue -->
<script src="../lib/vue2.7.8.js"></script>
</head>
<body>
<!-- 定义的容器 -->
<div id="app">
<!-- v-model叫指令,用来收集表单中的数据 -->
<!-- "people" 不是字符串 -->
<!-- input上面有一个value,表示输入框中的值 -->
<!-- 当输入框中的值修改了,那么data中的值也会修改 -->
<!--
按键修饰符:
.enter 回车键
.left 左键
.right 右键
.up 上键
.down 下键
.esc
.a
.b
.c
.....
-->
请输入你喜欢的人的名字,按回车打印出来:<input type="text" v-model="people" @keyup.enter="handle">
</div>
<script>
let vm = new Vue({
el:"#app",
data(){
return {
people:"wc"
}
},
methods:{
handle(e){
// console.log(e);
// if(e.keyCode === 13){
// console.log("你喜欢的人的名字是:", this.people);
// }
console.log("你喜欢的人的名字是:", this.people);
}
}
});
</script>
</body>
</html>
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
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