# 1.1.1 $emit 和 $on

<html>

<head>
  <meta charset="UTF-8" />
  <title>$emit 和 $on</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
  <div id="root">
    <button @click="triger">触发事件</button>
  </div>
  <script>
    new Vue({
      el: '#root',
      data() {
        return {
          message: 'hello vue'
        }
      },
      created() {
        this.$on('my_events', this.handleEvents)
      },
      methods: {
        handleEvents(e) {
          console.log(this.message, e)
        },
        triger() {
          this.$emit('my_events', 'my params')
        }
      }
    })
  </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

# 1.1.2 directive 用法

<html>

<head>
    <meta charset="UTF-8" />
    <title>directive 用法</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="root">
        <div v-loading="isLoading">{{data}}</div>
        <button @click="update">更新</button>
    </div>
    <script>
    Vue.directive('loading', {
        update(el, binding, vnode) {
            if (binding.value) {
                const div = document.createElement('div')
                div.innerText = '加载中...'
                div.setAttribute('id', 'loading')
                div.style.position = 'absolute'
                div.style.left = 0
                div.style.top = 0
                div.style.width = '100%'
                div.style.height = '100%'
                div.style.display = 'flex'
                div.style.justifyContent = 'center'
                div.style.alignItems = 'center'
                div.style.color = 'white'
                div.style.background = 'rgba(0, 0, 0, .7)'
                document.body.append(div)
            } else {
                document.body.removeChild(document.getElementById('loading'))
            }
        }
    })
    new Vue({
        el: '#root',
        data() {
            return {
                isLoading: false,
                data: ''
            }
        },
        methods: {
            update() {
                this.isLoading = true
                setTimeout(() => {
                    this.data = '用户数据'
                    this.isLoading = false
                }, 3000)
            }
        }
    })
    </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

# 1.1.3 Vue.component 用法

<html>

<head>
    <meta charset="UTF-8" />
    <title>Vue.component 用法</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="root">
        <Test></Test>
        <Test :msg="message"></Test>
    </div>
    <script>
    Vue.component('Test', {
        template: '<div>{{msg}}</div>',
        props: {
            msg: {
                type: String,
                default: 'default message'
            }
        }
    })
    new Vue({
        el: '#root',
        data() {
            return {
                message: "Test Component"
            }
        }
    })
    </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

# 1.1.4 Vue.extend 用法

<html>

<head>
    <meta charset="UTF-8" />
    <title>Vue.extend 用法</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="root">
        <Test :msg="message"></Test>
    </div>
    <script>
    const component = Vue.extend({
        template: '<div>{{msg}}</div>',
        props: {
            msg: {
                type: String,
                default: 'default message'
            }
        }
    })
    Vue.component('Test', component)
    new Vue({
        el: '#root',
        data() {
            return {
                message: "Test Extend Component"
            }
        }
    })
    </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

# 1.1.5 Vue.extend 进阶用法

Vue.extend 属于Vue 的全局 API,在实际业务开发中很少使用到,因为相比常用的 Vue.component 写法使用 extend 的步骤要繁琐一些。但是在一些独立组件开发场景中,Vue.extend + $mount 这对组合是我们需要关注的。

<html>

<head>
    <meta charset="UTF-8" />
    <title>Vue.extend 用法2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
    #loading-wrapper {
        position: fixed;
        top: 0;
        left: 0;
        display: flex;
        justify-content: center;
        align-items: center;
        width: 100%;
        height: 100%;
        background: rgba(0, 0, 0, .7);
        color: #fff;
    }
    </style>
</head>

<body>
    <div id="root">
        <button @click="showLoading">显示Loading</button>
    </div>
    <script>
    function Loading(msg) {
        const LoadingComponent = Vue.extend({
            template: '<div id="loading-wrapper">{{msg}}</div>',
            props: {
                msg: {
                    type: String,
                    default: msg
                }
            }
        })
        const div = document.createElement('div')
        div.setAttribute('id', 'loading-wrapper')
        document.body.append(div)
        new LoadingComponent().$mount('#loading-wrapper')
        return () => {
            document.body.removeChild(document.getElementById('loading-wrapper'))
        }
    }
    Vue.prototype.$loading = Loading
    new Vue({
        el: '#root',
        methods: {
            showLoading() {
                const hide = this.$loading('正在加载,请稍等...')
                setTimeout(() => {
                    hide()
                }, 2000)
            }
        }
    })
    </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

可以看到,extend 创建的是 Vue 构造器,而不是我们平时常写的组件实例,所以不可以通过 new Vue({ components: LoadingComponent }) 来直接使用,需要通过 new LoadingComponent().$mount('#loading-wrapper') 来挂载到指定元素上。

# 1.1.6 Vue.use 用法

<html>

<head>
    <meta charset="UTF-8" />
    <title>Vue.extend 用法2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
    #loading-wrapper {
        position: fixed;
        top: 0;
        left: 0;
        display: flex;
        justify-content: center;
        align-items: center;
        width: 100%;
        height: 100%;
        background: rgba(0, 0, 0, .7);
        color: #fff;
    }
    </style>
</head>

<body>
    <div id="root">
        <button @click="showLoading">显示Loading</button>
    </div>
    <script>
    const loadingPlugin = {
        install: function(Vue) {
            const LoadingComponent = Vue.extend({
                template: '<div id="loading-wrapper">{{msg}}</div>',
                props: {
                    msg: {
                        type: String,
                        default: 'loading...'
                    }
                }
            }, 'LoadingComponent')

            function Loading(msg) {
                const div = document.createElement('div')
                div.setAttribute('id', 'loading-wrapper')
                document.body.append(div)
                new LoadingComponent({
                    props: {
                        msg: {
                            type: String,
                            default: msg
                        }
                    }
                }).$mount('#loading-wrapper')
                return () => {
                    document.body.removeChild(document.getElementById('loading-wrapper'))
                }
            }

            Vue.prototype.$loading = Loading
        }
    }

    Vue.use(loadingPlugin)
    new Vue({
        el: '#root',
        methods: {
            showLoading() {
                const hide = this.$loading('正在加载,请稍等...')
                setTimeout(() => {
                    hide()
                }, 2000)
            }
        }
    })
    </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

# 1.1.7 组件通信 provide 和 inject

<html>

<head>
    <meta charset="UTF-8" />
    <title>组件通信 provide 和 inject</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="root">
        <Test></Test>
    </div>
    <script>
    function registerPlugin() {
        Vue.component('Test', {
            template: '<div>{{message}}<Test2 /></div>',
            provide() {
                return {
                    elTest: this
                }
            }, // function 的用途是为了获取运行时环境,否则 this 将指向 window
            data() {
                return {
                    message: 'message from Test'
                }
            },
            methods: {
                change(component) {
                    this.message = 'message from ' + component
                }
            }
        })
        Vue.component('Test2', {
            template: '<Test3 />'
        })
        Vue.component('Test3', {
            template: '<button @click="changeMessage">change</button>',
            inject: ['elTest'],
            methods: {
                changeMessage() {
                    this.elTest.change(this.$options._componentTag)
                }
            }
        })
    }
    Vue.use(registerPlugin)
    var z = new Vue({
        el: '#root'
    })
    </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

# 1.1.8 过滤器 filter

<html>

<head>
    <meta charset="UTF-8" />
    <title>过滤器 filter</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="root">
        {{message | lower}}
    </div>
    <script>
    new Vue({
        el: '#root',
        filters: {
            lower(value) {
                return value.toLowerCase()
            }
        },
        data() {
            return {
                message: 'Hello Vue'
            }
        }
    })
    </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

# 1.1.9 监听器 watch

<html>

<head>
    <meta charset="UTF-8" />
    <title>监听器 watch</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="root">
        <h3>Watch 用法1:常见用法</h3>
        <input v-model="message">
        <span>{{copyMessage}}</span>
    </div>
    <div id="root2">
        <h3>Watch 用法2:绑定方法</h3>
        <input v-model="message">
        <span>{{copyMessage}}</span>
    </div>
    <div id="root3">
        <h3>Watch 用法3:deep + handler</h3>
        <input v-model="deepMessage.a.b">
        <span>{{copyMessage}}</span>
    </div>
    <div id="root4">
        <h3>Watch 用法4:immediate</h3>
        <input v-model="message">
        <span>{{copyMessage}}</span>
    </div>
    <div id="root5">
        <h3>Watch 用法5:绑定多个 handler</h3>
        <input v-model="message">
        <span>{{copyMessage}}</span>
    </div>
    <div id="root6">
        <h3>Watch 用法6:监听对象属性</h3>
        <input v-model="deepMessage.a.b">
        <span>{{copyMessage}}</span>
    </div>
    <script>
    new Vue({
        el: '#root',
        watch: {
            message(value) {
                this.copyMessage = value
            }
        },
        data() {
            return {
                message: 'Hello Vue',
                copyMessage: ''
            }
        }
    })
    new Vue({
        el: '#root2',
        watch: {
            message: 'handleMessage'
        },
        data() {
            return {
                message: 'Hello Vue',
                copyMessage: ''
            }
        },
        methods: {
            handleMessage(value) {
                this.copyMessage = value
            }
        }
    })
    new Vue({
        el: '#root3',
        watch: {
            deepMessage: {
                handler: 'handleDeepMessage',
                deep: true
            }
        },
        data() {
            return {
                deepMessage: {
                    a: {
                        b: 'Deep Message'
                    }
                },
                copyMessage: ''
            }
        },
        methods: {
            handleDeepMessage(value) {
                this.copyMessage = value.a.b
            }
        }
    })
    new Vue({
        el: '#root4',
        watch: {
            message: {
                handler: 'handleMessage',
                immediate: true,
            }
        },
        data() {
            return {
                message: 'Hello Vue',
                copyMessage: ''
            }
        },
        methods: {
            handleMessage(value) {
                this.copyMessage = value
            }
        }
    })
    new Vue({
        el: '#root5',
        watch: {
            message: [{
                    handler: 'handleMessage',
                },
                'handleMessage2',
                function(value) {
                    this.copyMessage = this.copyMessage + '...'
                }
            ]
        },
        data() {
            return {
                message: 'Hello Vue',
                copyMessage: ''
            }
        },
        methods: {
            handleMessage(value) {
                this.copyMessage = value
            },
            handleMessage2(value) {
                this.copyMessage = this.copyMessage + '*'
            }
        }
    })
    new Vue({
        el: '#root6',
        watch: {
            'deepMessage.a.b': 'handleMessage'
        },
        data() {
            return {
                deepMessage: {
                    a: {
                        b: 'Hello Vue'
                    }
                },
                copyMessage: ''
            }
        },
        methods: {
            handleMessage(value) {
                this.copyMessage = value
            }
        }
    })
    </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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167

# 1.1.10 class 和 style 绑定的高级用法

<html>

<head>
    <meta charset="UTF-8" />
    <title>class 和 style 绑定的高级用法</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="root">
        <div :class="['active', 'normal']">数组绑定多个class</div>
        <div :class="[{active: isActive}, 'normal']">数组包含对象绑定class</div>
        <div :class="[showWarning(), 'normal']">数组包含方法绑定class</div>
        <div :style="[warning, bold]">数组绑定多个style</div>
        <div :style="[warning, mix()]">数组包含方法绑定style</div>
        <div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }">style多重值</div>
    </div>
    <script>
    new Vue({
        el: '#root',
        data() {
            return {
                isActive: true,
                warning: {
                    color: 'orange'
                },
                bold: {
                    fontWeight: 'bold'
                }
            }
        },
        methods: {
            showWarning() {
                return 'warning'
            },
            mix() {
                return {
                    ...this.bold,
                    fontSize: 20
                }
            }
        }
    })
    </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

# 1.1.11 Vue.observable

<html>

<head>
    <meta charset="UTF-8" />
    <title>Vue.observable</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="root">
        {{message}}
        <button @click="change">Change</button>
    </div>
    <script>
    const state = Vue.observable({
        message: 'Vue 2.6'
    })
    const mutation = {
        setMessage(value) {
            state.message = value
        }
    }
    new Vue({
        el: '#root',
        computed: {
            message() {
                return state.message
            }
        },
        methods: {
            change() {
                mutation.setMessage('Vue 3.0')
            }
        }
    })
    </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

# 1.1.12 插槽 slot

<html>

<head>
    <meta charset="UTF-8" />
    <title>插槽 slot</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="root">
        <div>案例1:slot的基本用法</div>
        <Test>
            <template v-slot:header="{user}">
                <div>自定义header({{user.a}})</div>
            </template>
            <template v-slot="{user}">
                <div>自定义body({{user.b}})</div>
            </template>
        </Test>
    </div>
    <hr>
    <div id="root2">
        <div>案例2:Vue2.6新特性 - 动态slot</div>
        <Test>
            <template v-slot:[section]="{section}">
                <div>this is {{section}}</div>
            </template>
        </Test>
        <button @click="change">switch header and body</button>
    </div>
    <script>
    Vue.component('Test', {
        template: '<div>' +
            '<slot name="header" :user="obj" :section="\'header\'">' +
            '<div>默认header</div>' +
            '</slot>' +
            '<slot :user="obj" :section="\'body\'">默认body</slot>' +
            '</div>',
        data() {
            return {
                obj: {
                    a: 1,
                    b: 2
                }
            }
        }
    })
    new Vue({
        el: '#root'
    })
    new Vue({
        el: '#root2',
        data() {
            return {
                section: 'header'
            }
        },
        methods: {
            change() {
                this.section === 'header' ?
                    this.section = 'default' :
                    this.section = 'header'
            }
        }
    })
    </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