Vue 中组件关系可分为父子组件通信、兄弟组件通信、跨级组件通信。本节将介绍 “prop”、”$emit、$on”、 “中央事件总线(bus)”、”$parent、$children”的使用方式。
组件之间通信可以用下图表示:
组件通信示例
下面将介绍组件之间通信的实现方式
1. prop
父组件可以使用 props 把数据传给子组件
将父组件的数据 myMessage 通过设置标签 my-child 的 message 属性传递给子组件,子组件通过 props 传递接受,在子组件内 message 就是 父组件的 myMessage 数据。
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> <my-child :message="myMessage"></my-child> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <script> Vue.component("my-child", { props: ["message"], template: "<div>{{ message }}</div>" })
var vm = new Vue({ el: "#app", data() { return { myMessage: "hello world" } } }) </script> </html>
|
注意:
某些组件在使用的时候,对传入的数据有类型要求。因此,我们可以为组件的prop 指定验证要求。可以为 props 中的值提供一个带有验证需求的对象,而不是一个字符串数组。例如:
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
| Vue.component("my-child", { props: { message: Number, message_1: [String, Number], message_2: { type: String, required: true }, message_3: { type: Number, default: 100 }, message_4: { type: Object, default: function () { return { name: "尼古拉斯赵四" } } }, message_5: { validator: function (value) { return ["success", "warning", "danger"].indexOf(value) !== -1 } } }, template: "<div>{{ message }}</div>" })
|
2. $emit、$on
子组件可以使用 $emit 触发父组件的自定义事件
1 2
| vm.$emit(event, arg); // 触发当前实例上的事件 vm.$on(event, fn); // 监听event事件后运行 fn
|
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> <div> 数量: {{ total }} </div> <my-child @update="parentUpdate"></my-child> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <script> Vue.component("my-child", { template: '<button @click="childUpdate">+1</button>', methods: { childUpdate() {
this.$emit("update", 1); } } })
var vm = new Vue({ el: "#app", data: function () { return { total: 1 } }, methods: { parentUpdate(val) { this.total += 1; } } }) </script> </html>
|
3. bus (使用一个空的 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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> <div> 姓名: {{ name }}</div> <div> 年龄: {{ age }}</div> <my-child></my-child> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <script> var bus = new Vue({ data() { return { name: "大東" } } });
Vue.component("my-child", { template: '<button @click="childUpdate">+1</button>', methods: { childUpdate() { bus.name = "大東博客"; bus.$emit("update", 1); } } })
var vm = new Vue({ el: "#app", data: function () { return { age: 1 } }, computed: { name() { return bus.name; } }, mounted: function() { var _this = this; bus.$on("update", function(val) { _this.age += val; }); } }) </script> </html>
|
4. $parent、$children
在子组件中, 使用 this.$parent 可以直接访问改组件的父实例或组件,父组件也可以通过 this.$children 访问它所有的子组件,而且可以递归向上或向下无限访问,直到根实例或最内层的组件。
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 name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> <div> 姓名: {{ name }}</div> <div> 年龄: {{ age }}</div> <my-child></my-child> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <script>
Vue.component("my-child", { template: '<button @click="childUpdate">+1</button>', methods: { childUpdate() { this.$parent.updateAge(); } } })
var vm = new Vue({ el: "#app", data: function () { return { age: 1, name: "大東博客" } }, methods: { updateAge: function() { this.age += 1; } } }) </script> </html>
|
注意:
在父组件模板中,子组件标签上使用 ref 指定一个名称,并在父组件内通过 this.$refs 来访问指定名称的子组件。