前言
組件是 vue.js 最強大的功能之一,而組件實例的作用域是相互獨立的,這就意味著不同組件之間的數(shù)據(jù)無法相互引用,那么組件之間的通信顯得非常重要。
以下總結(jié)了 vue 組件間通信的幾種方式
方法一、props/$emit
1.父組件向子組件傳值
父組件通過 props 向下傳遞數(shù)據(jù)給子組件
2.子組件向父組件傳值
子組件傳遞數(shù)據(jù)給父組件是通過$emit觸發(fā)事件來做到的
//父組件
</template>
<div class="comments">
<!-- 精彩評論 -->
<Hot-c
:hotComments="comments.hotComments" // 傳遞參數(shù),傳遞給子組件
:moreHot="comments.moreHot"
@toPraise="toPraise" // 傳遞事件,用于接受子組件數(shù)據(jù)
/>
</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:{ //這個就是父組件中子標(biāo)簽自定義名字
type:String,
required:true
}
},
methods: {
click() {
this.$emit('toPraise', 'liked') // 第一個參數(shù)為事件名,第二參數(shù)為要傳遞的值
}
}
}
</script>
方法二、emit / $on
事件總線
這種方法通過一個空的 Vue 實例作為中央事件總線(事件中心),用它來觸發(fā)事件和監(jiān)聽事件,巧妙而輕量地實現(xiàn)了任何組件間的通信,包括父子、兄弟、跨級。當(dāng)我們的項目比較大時,可以選擇更好的狀態(tài)管理解決方案 vuex。
// main.js
Vue.prototype.$eventBus = new Vue() // 可以放在vue原型上,也可以單獨建個js創(chuàng)建空的vue實例
//父組件
this.$eventBus.$emit(事件名,數(shù)據(jù))
//子組件
this.$eventBus.$on(事件名,data => {});
事件總線使用起來很方便,但是如果不正確的使用,將會是一場災(zāi)難,組件如果被循環(huán)得創(chuàng)建和銷毀,eventBus的我們監(jiān)聽需要手動移除,不然因為外部的引用會一直存在,在后期被反復(fù)觸發(fā),因此所有$eventBus的監(jiān)聽需要我們在組件銷毀時候?qū)⒈O(jiān)聽進行移除
beforDestory(){
this.$eventBus.$off ("事件名" )
}
方法三、provide/inject
provide / inject API 主要解決了跨級組件間的通信問題,不過它的使用場景,主要是子組件獲取上級組件的狀態(tài),跨級組件間建立了一種主動提供與依賴注入的關(guān)系。
// A.vue
export default {
provide: {
name: 'msg'
}
}
// B.vue
export default {
inject: ['name'],
mounted () {
console.log(this.name); // msg
}
}
需要注意的是:provide 和 inject 綁定并不是可響應(yīng)的。這是刻意為之的。然而,如果你傳入了一個可監(jiān)聽的對象,那么其對象的屬性還是可響應(yīng)的----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');
}
}
}
不過,這兩種方法的弊端是,無法在跨級或兄弟間通信