前言
组件是 vue.js 最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用,那么组件之间的通信显得非常重要。
以下总结了 vue 组件间通信的几种方式
方法一、props/$emit
1.父组件向子组件传值
父组件通过 props 向下传递数据给子组件
2.子组件向父组件传值
子组件传递数据给父组件是通过$emit触发事件来做到的
//父组件
</template>
<div class="comments">
<!-- 精彩评论 -->
<Hot-c
:hotComments="comments.hotComments" // 传递参数,传递给子组件
:moreHot="comments.moreHot"
@toPraise="toPraise" // 传递事件,用于接受子组件数据
/>
</div>
</template>
<script>
import HotC from './hotC/index.vue'
export default {
name: 'App',
data(){
return{
comments: { comments: '最新评论', hotComments: '精彩评论', moreHot: false}
}
},
components:{
HotC
}
},
methods: {
toPraise(msg) { // msg是子组件传递过来的
this.comments.moreHot = true
console.log(msg) // liked
}
}
</script>
//子组件
<template>
<div @click="click">
{{ hotComments }} // 直接使用
</div>
</template>
<script>
export default {
props:{
hotComments:{ //这个就是父组件中子标签自定义名字
type:String,
required:true
}
},
methods: {
click() {
this.$emit('toPraise', 'liked') // 第一个参数为事件名,第二参数为要传递的值
}
}
}
</script>
方法二、emit / $on
事件总线
这种方法通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。当我们的项目比较大时,可以选择更好的状态管理解决方案 vuex。
// main.js
Vue.prototype.$eventBus = new Vue() // 可以放在vue原型上,也可以单独建个js创建空的vue实例
//父组件
this.$eventBus.$emit(事件名,数据)
//子组件
this.$eventBus.$on(事件名,data => {});
事件总线使用起来很方便,但是如果不正确的使用,将会是一场灾难,组件如果被循环得创建和销毁,eventBus的我们监听需要手动移除,不然因为外部的引用会一直存在,在后期被反复触发,因此所有$eventBus的监听需要我们在组件销毁时候将监听进行移除
beforDestory(){
this.$eventBus.$off ("事件名" )
}
方法三、provide/inject
provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。
// A.vue
export default {
provide: {
name: 'msg'
}
}
// B.vue
export default {
inject: ['name'],
mounted () {
console.log(this.name); // msg
}
}
需要注意的是:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的----vue 官方文档
方法四、children与 ref
ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
children:访问父 / 子实例
//父组件
</template>
<div class="comments">
<!-- 精彩评论 -->
<Hot-c ref="hot"/>
</div>
</template>
<script>
export default {
mounted () {
const comA = this.$refs.comA;
console.log(comA.title); // Vue.js
comA.sayHello(); // 弹窗
}
}
</script>
//子组件
export default {
data () {
return {
title: 'Vue.js'
}
},
methods: {
sayHello () {
window.alert('Hello');
}
}
}
不过,这两种方法的弊端是,无法在跨级或兄弟间通信