组件通信无外乎以下几种情况:
- 父子通信
- 子向父通信
- 同级通信
- 跨层级通信
- 任意组件
1. 父子通信
props
父子通信是最常见的通信方式,父组件通过props
将数据传递到子组件,所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| Vue.component("child", { props: { name: String, age: Number }, template: "<div>name: {{name}}, age: {{age}}</div>" }); new Vue({ el: "#app", template: '<child :name="name" :age="age"></child>', data: { name: "小明", age: 3 } });
|
非 props
一个非 prop 特性是指传向一个组件,但是该组件并没有相应 prop 定义的特性。
非 props 特性会自动添加到组件的根元素上,除非手动禁止。
live demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| Vue.component("child-inner", { props: { name: String, age: Number }, template: "<div class='child-inner'> {{name}}, age: {{age}}</div>" }); Vue.component("child", { props: { name: String, age: Number }, template: '<div class="child"> <child-inner :name="name" :age="age"></child-inner></div>' }); new Vue({ el: "#app", template: ' <child notProps="hello" :name="name" :age="age"></child>', data: { name: "小明", age: 3 } });
|
生成的 html 结构如下,可以看到非 props 属性挂载到了编译好的 html 模板的最外层元素上。
如果想禁止集成这些非 props 属性,需要手动设置
1 2 3 4
| Vue.component("my-component", { inheritAttrs: false });
|
2. 子向父通信
在 vue 中一般通过 $emit
自定义事件,抛出事件到父组件中进行通信。
1 2
| this.$emit("change", value);
|
1
| // 父组件 <child @change="onChange" />
|
3. 同级通信
同级通信方式,需要将数据传递给父组件,父组件再将数据传递给另一个子组件。这个就不再赘述。
1 2 3 4
| <div> <child1 :age="age" @change="onChangeAge" /> <child2 :age="age" /> </div>
|
4. 跨层级通信
与 React 的 Context API 类似,Vue 也提供跨层级的通信方式 provide / inject
live demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| Vue.component("child-inner", { inject: ["foo"], created() { console.log(this.foo); }, template: "<div>{{foo}}</div>" });
Vue.component("child", { inject: ["foo"], created() { console.log(this.foo); }, template: "<div>{{foo}}inner: <child-inner /></div>" });
new Vue({ el: "#app", provide: { foo: "bar" }, data: {}, template: "<div><child /></div>" });
|
5. 任意组件
任意两个组件,这两个组件可能非嵌套关系,他们的通信需要依赖事件来处理。
在 React 中我们依赖了 events 包,在 Vue 中,Vue 本身提供事件方法。
1 2 3
| <div id="app1"></div> <div id="app2"></div>
|
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
| const Bus = new Vue();
const app1 = new Vue({ el: "#app1",
data: { msg: "hello" },
methods: { sendMsg: function(msg) { Bus.$emit("msg", msg); } }, created() { Bus.$on("msg", e => { this.msg = e; }); }, beforeDestroy() { Bus.$off("msg"); }, template: "<div>{{msg}}, app1</div>" });
new Vue({ el: "#app2",
data: { msg: "hello" }, created() { Bus.$on("msg", e => { this.msg = e; }); }, beforeDestroy() { Bus.$off("msg"); }, template: "<div>{{msg}}, app2</div>" });
app1.sendMsg("hello world!");
|