Vue 组件间通信主要指以下 3 类通信:父子组件通信、隔代组件通信、兄弟组件通信。
通信方式及用法:
1、props / $emit 适用父子组件通信
父组件向子组件传递数据是通过props传递的,子组件传递给父组件是通过$emit触发事件来做到的。
使用方法:
父组件 A.vue
<template>
<div style="background-color: skyblue;width: 300px">
<h3>这是A</h3>
// 向B传入了一个属性和一个方法
<b-child :nameB="nameB" @changeName="changeName"></b-child>
</div>
</template>
<script>
import BChild from "./B.vue";
export default {
name: "A",
components: {BChild},
data() {
return {
nameB: '这是子组件B'
}
},
methods: {
changeName(nameB) {
this.nameB = nameB;
}
}
}
</script>
子组件B.vue
<template>
<div style="background-color: pink;">
<h3>{{ nameB}}</h3>
<button @click="changeName">更改名字</button>
</div>
</template>
<script>
export default {
name: "B",
props: ['nameB'],// 接收A传递过来的属性
methods: {
changeName() {
this.$emit('changeName', '我是A的子组件B');// 调用A传过来的方法
}
}
}
</script>
2、ref / children 适用父子组件通信
ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例。
children:访问父 / 子实例。
使用方法:
父组件 A.vue
<template>
<div style="background-color: skyblue;width: 300px">
<h3>这是A</h3>
<b-child ref="child"></b-child>
</div>
</template>
<script>
import BChild from "./B.vue";
export default {
name: "A",
components: {BChild},
mounted() {
//通过$ref调用B的方法
this.$refs.child.getName();
//通过$children调用B的方法
//注意:$children返回的是一个数组,当有多个子组件的时候注意区分
this.$children[0].getName();
}
}
</script>
子组件 B.vue
<template>
<div style="background-color: pink;">
<h3>{{ name }}</h3>
</div>
</template>
<script>
export default {
name: "B",
data() {
return {
name: '我是A的子组件B'
}
},
methods: {
getName() {
console.log(this.name);
}
}
}
</script>
3、EventBus 适用于父子、隔代、兄弟组件通信
这种方法通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现任何组件间的通信,包括父子、隔代、兄弟组件。
使用方法:
先在main.js引入
import Vue from 'vue'
Vue.prototype.$EventBus = new Vue();
隔代组件 A.vue
<template>
<div style="background-color: skyblue;width: 300px">
<h3>这是A</h3>
<b-child ref="child"></b-child>
</div>
</template>
<script>
import BChild from "./B.vue";
export default {
name: "A",
components: {BChild},
mounted() {
this.$EventBus.$on('getMessage', (message) => {
console.log('这是C的message信息:', message);
})
},
beforeDestroy() {
console.log('----销毁监听事件,负责会导致了内存泄露----')
this.$EventBus.$off('getMessage');
}
}
</script>
隔代组件 C.vue
<template>
<div style="background-color: yellow;">
<h3>这是C</h3>
<button @click="sendMessage">向A发送信息</button>
</div>
</template>
<script>
export default {
name: "C",
methods: {
sendMessage() {
this.$EventBus.$emit('getMessage', 'yes');
}
}
}
</script>
4、attr / listeners 适用于隔代组件通信
使用方法:
父组件 A.vue
<template>
<div style="background-color: skyblue;width: 300px">
<h3>这是A</h3>
<b-child nameB="这是B" nameC="这是C" @handleClick="handleClick"></b-child>
</div>
</template>
<script>
import BChild from "./B.vue";
export default {
name: "A",
components: {BChild},
methods: {
handleClick() {
console.log('事件触发了');
}
},
}
</script>
A的子组件 B.vue
<template>
<div style="background-color: pink;">
<h3>{{ nameB }}</h3>
<!-- 通过 v-bind 绑定$attrs属性,C组件可以直接获取到A组件中传递下来的props(除了B组件中props声明的) -->
<!-- 通过 v-on 绑定了$listeners 属性 -->
<c-child v-bind="$attrs" v-on="$listeners"></c-child>
</div>
</template>
<script>
import CChild from "./C.vue";
export default {
name: "B",
components: {CChild},
props: ["nameB"]
}
</script>
B的子组件 C.vue
<template>
<div style="background-color: yellow;">
<h3>{{ nameC }}</h3>
<button @click="handleClick">点击</button>
</div>
</template>
<script>
export default {
name: "C",
props: ["nameC"],
methods: {
handleClick() {
this.$emit('handleClick');
}
}
}
</script>
5、provide / inject 适用于隔代组件通信
祖先组件中通过 provider 来提供变量,然后在子孙组件中通过 inject 来注入变量。provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。
使用方法:
父组件 A.vue
<template>
<div style="background-color: skyblue;width: 300px">
<h3>这是A</h3>
<b-child nameB="这是B"></b-child>
</div>
</template>
<script>
import BChild from "./B.vue";
export default {
name: "A",
components: {BChild},
provide() {
return {
btnClick: this.handleClick// 传递
}
},
methods: {
handleClick() {
console.log('事件触发了');
}
},
}
</script>
子组件 B.vue
<template>
<div style="background-color: pink;">
<h3>{{ nameB }}</h3>
<button @click="handleClick">点击</button>
</div>
</template>
<script>
export default {
name: "C",
props: ["nameB"],
inject: ["btnClick"],// 接收
methods: {
handleClick() {
this.btnClick();
}
}
}
</script>
6、Vuex 适用于 父子、隔代、兄弟组件通信
Vuex在这里就不做讲解了,详情查看 vuex文档