Vue组件通信模式

概述

在Vue.js中,有几种我们能用的内部组件通信的方法。一般的属性和事件对于大多数场景来说已经够用了,但是除此之外,还有其他可用的方法。

属性和事件

当然,一般的通信方法用到了属性和事件。这种常用的模式是组件中一种强大的通信方式,它不用在相关的组件上引入任何依赖和限制。

属性

属性允许你传递任意的数据类型到一个子组件中,并且允许你控制组件接收何种类型的数据。属性的更新也是响应式的,这使得无论任何时候,父组件的数据改变,子组件就会更新。

模板用法:

1
2
3
<my-component v-bind:prop1="parentValue"></my-component>
<!-- Or more succinctly, -->
<my-component :prop1="parentValue"></my-component>

事件

事件提供了一种子组件通知父组件做出改变的方式。

模板用法:

1
2
3
<my-component v-on:myEvent="parentHandler"></my-component>
<!-- Or more succinctly, -->
<my-component @myEvent="parentHandler"></my-component>

触发一个事件:

1
2
3
4
5
6
7
8
// ...
export default {
methods: {
fireEvent() {
this.$emit('myEvent', eventValueOne, eventValueTwo);
}
}
}

Additionally, you can create global event buses to pass events anywhere in your app. We’ve got an article on that.

此外,你还可以创建一个全局事件总线来在任意位置传递事件。这里有一篇相关的文章

组合使用

使用v-model可以结合属性和事件以实现双向绑定。这经常用于输入组件中。v-model假定了值属性和输入事件,但是这个可以根据自身需要来设置。

模板用法:

1
<my-component v-model="prop1"></my-component>

一个v-model兼容的组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<div>
<input type="text" :value="value" @input="triggerEvent"/>
</div>
</template>

<script>
export default {
props: {
value: String
},

methods: {
triggerEvent(event) {
this.$emit('input', event.target.value);
}
}
}
</script>

当你需要在组件之间做非常多的各种各样的数据传递和消息通讯的时候,可以用这种方式。

Provide / Inject

provide/inject机制是Vue一个比较新的特性。它可以选择性的暴露祖先组件的数据或者方法到其所有的后代中。由于provide/inject自身不是响应式的,它可以用来传递响应式对象。

对于开发应用而言,provice/inject也许不是一个好的选择,但是当写一个完整的自定义渲染组件库时,它就十分顺手了。

祖先组件:

1
2
3
4
5
6
7
const SomethingAllDescendantsNeed = 'Air, probably.';

export default {
provide: {
SomethingAllDescendantsNeed
}
}

后代组件

1
2
3
4
5
6
7
export default {
inject: ['SomethingAllDescendantsNeed'],

mounted() {
console.log(this.SomethingAllDescendantsNeed);
}
}

模板使用:

1
2
3
4
5
6
7
8
9
<ancestor-component>
<div>
<descendant-component>
<p>
<descendant-component></descendant-component>
</p>
</descendant-component>
</div>
</ancestor-component>

(所有的后代组件,无论在组件树中有多深,都能获取SomethingAllDescendantsNeeds)

当子组件需要使用一个组件树只初始化一次时创建的实例时(比如另一个库或者一个事件总线时)。

直接访问

警告:危险

如果你真的,真的,真的需要直接访问一个父组件或者子组件,你可以使用所有组件都有的this.$parent和this$.children属性,它们拥有父组件和子组件所有的权限。但这个做法,是非常极其一定以及肯定地可怕的想法。如果你发现处于某种需要这么做的场景,那99.99958%的概率你在什么地方做错了,而且应该重构。

什么时候用这种方法呢:别用,就是,别用。

为什么别用呢?因为你在父子组件的实现和结构上直接引入了耦合,使组件的可扩展性几乎极大地降低。

参考

  1. Vue.js Component Communication Patterns - Joshua Bemenderfer