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
<!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, 事件绑定

# 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.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, 事件修饰符

修饰符:

  • .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, 与表单元素一起使用的修饰符

<!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
Last Updated: 12/25/2022, 10:02:14 PM