組件是Vue.js強(qiáng)大的功能之一,而組件實(shí)例的作用域是相互獨(dú)立的,那么在開發(fā)的過程中踢俄,組件與組件之間肯定是相互聯(lián)系的睦疫,那么,組件之間是如何通信的,是如何傳遞數(shù)據(jù)的呢?
一: 幾種常見的組件
父子組件、兄弟組件俩檬、跨級組件;而相應(yīng)的通信也分為:父子組件通信碾盟、兄弟組件通信棚辽、跨級組件通信。
那么冰肴,針對不同的組件屈藐,我們?nèi)绾芜M(jìn)行通信呢?接下來我們來看一下都有哪些組件間的通信方式熙尉。
二: 組件間的通信方式
1. 父子組件通信(props/$emit
)
a. 父傳子 --- 父組件通過props
向下傳遞數(shù)據(jù)給子組件
父組件通過props
的方式來給子組件傳值联逻,例子:子組件son.app
如何獲取父組件App.vue
中的數(shù)據(jù)title
和lists
,動態(tài)傳值要結(jié)合使用v-bind
// App.vue 父組件
<template>
<div id="app">
// 1. 給 prop 傳遞一個靜態(tài)的值检痰,title 為 prop 的名稱(名稱為自定義名稱)包归,等號后面的為 prop 要傳遞的值
// 2. prop 通過 v-bind 動態(tài)賦值 , 前者 lists 為自定義名稱便于子組件調(diào)用,后者 list 為要傳遞數(shù)據(jù)名即 data中的 lists
<son title = "這是父組件傳來的靜態(tài)值" :lists="lists"></son>
</div>
</template>
<script>
import son from './components/son'
export default {
name: 'app',
components:{son},
data(){
return {
lists: ['寶玉','黛玉','寶釵']
}
}
}
</script>
// son.vue 子組件
<template>
<div class="son">
<div>{{title}}</div> // 渲染從父組件中接收到的數(shù)據(jù)
<ul>
<li v-for="list in lists" >{{list}}</li> // 遍歷傳遞過來的值铅歼,后渲染到頁面
</ul>
</div>
</template>
<script>
export default {
props: ['title','lists'] // 數(shù)組中的內(nèi)容就是父組件中子標(biāo)簽自定義名字
}
</script>
b. 子傳父
-
通過自定義事件模式
$on
和$emit
子組件使用$emit
來觸發(fā)事件公壤,父組件使用$on
來監(jiān)聽事件换可,一旦子組件觸發(fā)該事件,則父組件就會接收該事件并作出相應(yīng)處理境钟。類似與JavaScript
中的發(fā)布訂閱模式锦担。
-
vm.$on(evet,callback)
- 參數(shù)
-
{string | Array<string>} event
(數(shù)組只在 2.2.0+ 中支持) {Function} callback
-
- 用法
監(jiān)聽當(dāng)前實(shí)例上的自定義事件。事件可以由vm.$emit
觸發(fā)慨削。回調(diào)函數(shù)會接收所有傳入事件觸發(fā)函數(shù)的額外參數(shù)套媚。 - 示例:
vm.$on('test', function (msg) { console.log(msg) }) vm.$emit('test', 'hi') // => "hi"
- 參數(shù)
-
vm.$emit(evnetname,[...args])
- 參數(shù):
{string} eventName
-
[...args]
觸發(fā)當(dāng)前實(shí)例上的事件缚态。附加參數(shù)都會傳給監(jiān)聽器回調(diào)。
- 參數(shù):
下述代碼為堤瘤,子組件son.vue
向父組件App.vue
傳遞一個數(shù)據(jù)
// son.vue 子組件
<template>
<div class="son">
<button @click = "$emit('msghandle',msg)">點(diǎn)擊</button> // msghandle 為自定義事件的名字玫芦,msg 為要傳遞的數(shù)據(jù)
</div>
</template>
<script>
export default {
props: ['title','lists','acount'],
data(){
return {
msg: "這是從子組件傳遞過來的信息"
}
}
}
// App.vue 父組件
<template>
<div id="app">
<son @msghandle="handle"></son> // msghandle 事件名稱與子組件保持一致,handle 為回調(diào)函數(shù)本辐,接收傳遞過來的額外參數(shù)
<div>{{msg}}</div>
</div>
</template>
<script>
import son from './components/son'
export default {
name: 'app',
components:{son},
data(){
return {
msg:''
}
},
methods: {
handle(e){ // 執(zhí)行子組件觸發(fā)的事件 桥帆, e為子組件傳遞過來的參數(shù)
this.msg = e
}
}
}
</script>
上述代碼實(shí)現(xiàn)的功能,當(dāng)點(diǎn)擊 [點(diǎn)擊] 按鈕時慎皱,父組件中會接收并顯示來自組件的信息老虫。-
子傳父(在組件中使用
v--model
)
$emit
的代碼,這行代碼實(shí)際上會觸發(fā)一個 input
事件, input
后的參數(shù)就是傳遞給v--model
綁定 的屬性的值, v--model
其實(shí)是一個語法糖,這背后其實(shí)做了兩個操作
-
v--bind
綁定一個value
屬性,v--on
指令給當(dāng)前元素綁定input
事件 - 要使用
v--model
,要做到:接收一個value
屬性茫多。 在有新的value
時觸發(fā)input
事件
舉個例子:
// App.vue
<template>
<div id="app">
<son v-model="message"></son>
<p>{{message}}</p>
</div>
</template>
<script>
import son from './components/son'
export default {
name: 'app',
components:{son},
data(){
return {
message:'hello'
}
}
}
</script>
// son.vue
<template>
<div class="son">
<div>
<input type="text" v-model="mymessage" @change="change">
</div>
</div>
</template>
<script>
export default {
props: ['value'], //v-model 會自動傳遞一個字段為 value 的 props 屬性
data(){
return {
mymessage: this.value
}
},
methods: {
change() {
this.$emit('input', this.mymessage); //通過如此調(diào)用可以改變父組件上 v-model 綁定的值
}
}
</script>
在上面的實(shí)例代碼中祈匙,我們定義了App.vue
和 son.vue
兩個組件,這兩個組件是父子關(guān)系天揖,v-model
也只能實(shí)現(xiàn)父子組件之間的通信夺欲。
- 在
App.vue
組件中,我們給自定義的son
組件實(shí)現(xiàn)了v-model
綁定了message
屬性今膊。此時相當(dāng)于給son
組件傳遞了value
屬性和綁定了input
事件些阅。 - 順理成章,在定義的
son
組件中斑唬,可以通過props
獲取value
屬性市埋,根據(jù)props
單向數(shù)據(jù)流的原則,又將value
緩存在了data
里面的mymessage
上赖钞,再在input
上通過v-model
綁定了mymessage
屬性和一個change
事件腰素。當(dāng)input
值變化時,就會觸發(fā)change
事件雪营,處理App.vue
組件通過v-model
給son
組件綁定的input
事件弓千,觸發(fā)App
組件中message
屬性值的變化,完成son
子組件改變App
組件的屬性值献起。
2. 兄弟組件通信
這種方法通過一個空的Vue實(shí)例作為中央事件總線(事件中心)洋访,用它來觸發(fā)事件和監(jiān)聽事件,巧妙而輕量地實(shí)現(xiàn)了任何組件間的通信镣陕,包括父子、兄弟姻政、跨級呆抑。當(dāng)我們的項(xiàng)目比較大時,可以選擇更好的狀態(tài)管理解決方案vuex
- 大致步驟:
const bus = new Vue()
Vue.prototype.$bus = bus
$bus.$emit(事件名,數(shù)據(jù));
$bus.$on(事件名,data => {});
- 舉個例子
假設(shè)兄弟組件有三個汁展,分別是A鹊碍、B、C組件食绿,C組件如何獲取A或者B組件的數(shù)據(jù)
// 定義中央事件總線侈咕,并將中央事件總線掛在 Vue.prototype 上,這樣所有組件都能訪問到了
// main.js 文件
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
const bus = new Vue()
Vue.prototype.$bus = bus;
new Vue({
render: h => h(App),
}).$mount('#app')
// A.vue 組件A
<template>
<div>
<h3>A組件: {{name}}</h3>
<button @click = "send">將數(shù)據(jù)發(fā)給C組件</button>
</div>
</template>
<script>
export default {
data(){
return {
name: "Nick"
}
},
methods:{
send(){
this.$bus.$emit('data-a',this.name)
}
}
}
</script>
// B.vue 組件B
<template>
<div>
<h3>B組件:{{age}}</h3>
<button @click="send">將數(shù)據(jù)發(fā)給C組件</button>
</div>
</template>
<script>
export default {
data(){
return {
age: 30
}
},
methods:{
send(){
this.$bus.$emit('data-b',this.age)
}
}
}
</script>
<template>
<div>
<h3>C組件:{{name}} {{age}}</h3>
</div>
</template>
<script>
export default {
data(){
return {
name:'',
age:''
}
},
// mounted 在模板編譯后執(zhí)行
mounted(){
this.$bus.$on('data-a',name => {
this.name = name
})
this.$bus.$on('data-b',age => {
this.age = age
})
}
}
</script>
// App.vue 文件中
<template>
<div id="app">
<A></A>
<B></B>
<C></C>
</div>
</template>
<script>
import A from './components/A'
import B from './components/B'
import C from './components/C'
export default {
name: 'app',
// components:{son},
components:{A,B,C},
</script>
在上面的實(shí)例中器紧,我們定義了組件 A 和組件 B和組件C耀销,但三個組件之間沒有任何的關(guān)系。
1)铲汪、 首先我們通過 new Vue()
實(shí)例化了一個 Vue 的實(shí)例熊尉,也就是我們這里稱呼的中央事件總線 bus
,然后將其掛載Vue.prototype.$bus
掌腰,使得所有的業(yè)務(wù)邏輯組件都能夠訪問到狰住;
2)、 然后定義了組件 A辅斟,在組件 A 里面定義了一個處理的方法 send
转晰,主要定義觸發(fā)一個 data-a
事件,并傳遞一個參數(shù)士飒;然后定義了組件 B查邢,在組件 B 里面定義了一個處理的方法 send
,主要定義觸發(fā)一個 data-b
事件酵幕,并傳遞一個參數(shù)扰藕;
3). 最后定義了組件 C,在組件 C 里面的 mounted 生命周期監(jiān)聽了組件 A 和組件B里面定義的 data-a
和data-b
事件芳撒,并在回調(diào)函數(shù)里面執(zhí)行了一些邏輯處理邓深。
中央事件總線 bus
非常簡單,就是任意組件和組件之間打交道笔刹,沒有多余的業(yè)務(wù)邏輯芥备,只需要在狀態(tài)變化組件觸發(fā)一個事件,然后在處理邏輯組件監(jiān)聽該事件就可以舌菜。該方法非常適合小型的項(xiàng)目萌壳!