1. 前言
在Vue中,父子组件之间通信是比较容易的,父组件通过props传递数据给子组件,子组件通过emit事件传递数据到父组件。但是在实际的开发中,会遇到跨层级组件通信的情况,比如兄弟组件之间、祖先组件和后代组件之间。这时候就需要使用Vue提供的跨层级通信工具来解决这个问题。本文将介绍Vue中如何实现跨层级组件通信。
2. provide / inject
provide / inject可以实现祖先组件向后代组件传递数据,具体实现方式是祖先组件通过provide提供数据,后代组件通过inject注入数据。需要注意的是,provide和inject组合起来使用,会产生一些潜在的问题。因为provide和inject并不是响应式的,所以不建议在provide中直接提供复杂类型的数据。但是可以在provide中提供一个函数,通过函数返回一个响应式的对象。
2.1 provide示例
provide() {
return {
foo: 'bar'
}
}
在上面的例子中,我们在provide中提供了一个foo属性,并给了它字符串'bar'。这个foo属性会被传递给该组件的所有后代组件。
2.2 inject示例
inject: ['foo']
在上面的例子中,我们通过inject将provide中提供的foo属性注入到该组件。这样后代组件就能够访问到foo属性了。
一个完整的provide / inject使用示例:
<template>
<div>
<child-component/>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue'
export default {
components: {
ChildComponent
},
provide() {
return {
foo: 'bar',
getTemperature: () => this.temperature
}
},
data() {
return {
temperature: 20
}
}
}
</script>
在上面的例子中,我们在provide中除了提供了一个foo属性外,还提供了一个getTemperature方法,该方法返回的是当前组件中的temperature数据。这样后代组件就能够通过调用该方法获取到temperature属性了。
3. $attrs / $listeners
VUE提供了$attrs和$listeners两个属性,用以实现兄弟组件之间的通信。
3.1 $attrs
$attrs包含了父组件传递给子组件但是子组件没有Props声明的属性,这些属性可以在子组件中作为普通属性访问。通过将$attrs传递给子组件,使得父组件可以初始化子组件并将多余的属性、事件、Listener等传递给子组件,而无需在子组件上声明所有的属性。这样做可以减少在子组件中定义 Props 的折腾。
<template>
<div>
<child-component v-bind="$attrs"/>
</div>
</template>
在上面的例子中,我们将所有$attrs传递给了子组件。这样,父组件中所有传递给子组件但是未在子组件中声明的属性都会被传递给子组件。
3.2 $listeners
$listeners包含了父组件传递给子组件的事件监听器。我们可以通过将$listeners传递给一个子组件,使得该子组件能够响应父组件传递过来的事件。因为$listeners中保存了父组件传递过来的所有事件监听器,所以我们只需要将$listeners中的事件监听器绑定到子组件的事件上即可实现监听。
<template>
<div>
<child-component v-bind="$attrs" v-on="$listeners"/>
</div>
</template>
在上面的例子中,我们将所有$listeners传递给了子组件。这样,子组件就能够响应父组件传递过来的事件了。
4. eventBus
eventBus是通过创建一个Vue实例实现的,通过这个实例来实现不同组件之间通信。我们可以在任何地方引入这个Vue实例,然后通过触发事件和监听事件的方式来实现通信。
4.1 创建eventBus
import Vue from 'vue'
export default new Vue()
我们需要创建一个Vue实例,并且将实例作为导出模块。这使得我们可以在应用程序中的任何位置引入这个Vue实例。
4.2 在组件中使用eventBus
我们可以在组件中使用$emit方法来触发事件,还可以使用$on方法来监听事件。
// 发送事件
import eventBus from './eventBus.js'
eventBus.$emit('increase', 1)
// 监听事件
import eventBus from './eventBus.js'
eventBus.$on('increase', function (num) {
console.log(num)
})
5. Vuex
Vuex是Vue的状态管理库。它通过将组件的状态抽离到一个全局可访问的状态树中,使得应用程序中的各个组件都能够访问到同一个状态。通过这种方式,Vuex可以实现不同组件之间的通信。
5.1 创建Vuex Store
在Vuex中,我们需要创建一个状态树。可以通过使用Vue.use(Vuex)方法来安装Vuex,并且创建一个状态树。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
在上面的例子中,我们通过创建一个Vuex Store并且安装Vuex来创建了一个状态树。
5.2 在组件中使用Vuex
在组件中,我们可以通过使用computed和methods等Vue组件特性来获取状态树中的数据和方法,还可以通过mutations等方法来改变状态树中的数据。
<template>
<div>
{{ count }}
<button v-on:click="increment">Increment</button>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex'
export default {
computed: {
...mapState(['count'])
},
methods: {
...mapMutations(['increment'])
}
}
</script>
在上面的例子中,我们将count状态从Vuex state映射到了组件的计算属性中,并且将increment映射到了组件的方法中。这样,我们就能够在组件中使用count和increment了。
6. 总结
Vue中实现跨层级组件通信的方法有多种,每一种方法都有其优缺点。我们应该根据应用场景和实际需求来选择最适合的方法。provide / inject、$attrs / $listeners、eventBus和Vuex这些方法都是Vue中常见的解决方案,我们应该根据实际情况选择最合适的方法来进行跨层级组件通信。