組件間通訊簡單來講就是組件間進行數據傳遞。就像咱們平常的打電話,就是通信的一種方式,你把話說給我聽,我把話說給你聽,說的話就是數據。電話就是通信方式的一種。不管是 Vue 仍是 React ,都得進行組件間通訊。Vue 組件間通訊的方式介紹以下。javascript
最多見的就是父子之間的通訊,通訊是雙向的數據傳遞。vue
父組件向兒子組件傳遞數據的方式就是 經過 Prop 向子組件傳遞數據。java
//child.vue <template> <div> 我是兒子,我收到來自父親的數據爲 {{value}} </div> </template> <script> export default { props:{ value: String } }
//App.vue <template> <div id="app"> <Child :value="x" /> </div> </template> <script> import Child from './components/Child' export default { data(){ return { x: 'hi,child' } }, components:{ Child } } </script>
兒子組件向父組件傳遞數據的方式就是經過子組件內 $emit 觸發自定義事件,子組件使用時 v-on 綁定監聽自定義事件。app
這裏的 v-on 事件通訊是在子組件使用時做爲子組件的事件屬性自動進行監聽的。post
所以兒子組件向父組件傳遞數據,依賴於子組件使用時的自定義事件屬性。this
//child.vue <template> <div> 我是兒子,我收到來自父親的數據爲 {{value}} <button @click="sayHi"> 向父組件打招呼 </button> </div> </template> <script> export default { props:{ value: String }, methods:{ sayHi(){ this.$emit('sayHi','hi,parent!'); } } } </script>
//App.vue <template> <div id="app"> 我是父組件,我收到子組件傳來的數據爲 {{y}} <Child :value="x" @sayHi="y = $event"/> </div> </template> <script> import Child from './components/Child' export default { data(){ return { x: 'hi,child', y: '' } }, components:{ Child } } </script>
爺孫間通訊,可使用兩次 v-on 通訊,爺爺爸爸通訊,而後爸爸兒子通訊。spa
也可以使用下方的任意組件間通訊的方式。prototype
任意組件間通訊就再也不區分是 A 向 B 通訊,仍是 B 向 A 通訊,而是通用的方式,誰想發送數據就使用對應的 API 發送數據,誰想要接收什麼數據,就使用對應的 API 接收。code
任意組件間通訊有兩種方式,一種是使用 EventBus 發佈訂閱模式通訊,一種是使用 Vuex 通訊。component
EventBus ,從字面意思理解就是事件公交車,全部觸發的事件傳遞的數據都從前門上車保存到公交車上,而後經過監聽對應事件提供的出口讓對應的事件數據下車。
EventBus,實際意思是發佈和訂閱模式,就是誰想把數據傳遞出去,就要經過觸發自定義事件的 API 進行數據的發佈;誰須要接收該數據信息的,就經過事件監聽的 API 進行數據的監聽,一旦檢測到監聽的數據發佈出來,就會接收,這就是數據的訂閱。
EventBus 通訊方式最重要是搞明白髮布和訂閱的接口 API,在 Vue 中,Vue 實例有提供兩個接口,即 $emit
和 $on
,所以能夠新建立一個空的 Vue 實例,來得到這兩個接口。
const eventBus = new Vue(); eventBus.$emit(eventName, […args]) //發佈事件 eventBus.$on(event, callback) //訂閱事件
實例以下:
// eventBus.js import Vue from 'vue' export const eventBus = new Vue();
//child <template> <div> 我是兒子,我收到來自父親的數據爲 <strong>{{value}}</strong> <button @click="sayHi"> 向父組件打招呼 </button> <button @click="sibling"> 向兄弟組件打招呼 </button> </div> </template> <script> import {eventBus} from '../eventBus.js' export default { props:{ value: String }, methods:{ sayHi(){ this.$emit('sayHi','hi,parent!'); }, sibling(){ eventBus.$emit('sibling','hi,brother'); } } } </script> <style scoped> strong{ color: red; } </style>
//sibling <template> <div> 我是兄弟組件,我收到來自兒子組件的數據信息爲 <strong>{{x}}</strong> </div> </template> <script> import {eventBus} from '../eventBus.js' export default { data(){ return { x: '' } }, mounted(){ eventBus.$on('sibling', (msg)=>{ this.x = msg; }) } } </script> <style scoped> strong{ color: green; } </style>
//parent <template> <div id="app"> 我是父組件,我收到子組件傳來的數據爲 <strong>{{y}}</strong> <Child :value="x" @sayHi="y = $event"/> <Sibling></Sibling> </div> </template> <script> import Child from './components/Child' import Sibling from './components/Sibling' export default { data(){ return { x: 'hi,child', y: '' } }, components:{ Child, Sibling } } </script> <style scoped> strong{ color: blue; } </style>
關於 EventBus 這部分,可能存在這樣一個疑問,既然 Vue 實例中都有 $emit
和 $on
,爲何不直接用 this.$emit
觸發事件, this.$on
接收事件呢?還非得要額外一個空實例 eventBus = new Vue() 。那是由於,Vue 中每一個組件都是一個單獨的 Vue 實例,你在這個 Vue 實例中觸發該實例的 emit 事件,另一個實例的 on 事件是接收不到的,不在一輛公交車上,怎麼能進行事件通訊呢?所以就必需要一個公共的公交車,也就是事件總線。
上述實例中的 eventBus 的使用方法是局部的 eventBus,誰要用到 eventBus 要本身手動引入。也能夠將 eventBus 作成全局的,好比掛在 vue 的原型上。
//main.js import Vue from 'vue' import App from './App.vue' Vue.config.productionTip = false Vue.prototype.$eventBus = new Vue();//添加這句,必定要在下方的 new Vue 前。 new Vue({ render: h => h(App), }).$mount('#app')
//child sibling(){ this.$eventBus.$emit('sibling','hi,brother'); }
//sibling mounted(){ this.$eventBus.$on('sibling', (msg)=>{ this.x = msg; }) }
除了上述的添加屬性到 Vue 原型的方式外,還可使用 Object.defineProperty()
爲 Vue 原型添加屬性。
import Vue from 'vue' import App from './App.vue' Vue.config.productionTip = false let eventBus = new Vue() Object.defineProperty(Vue.prototype,'$eventBus',{ get(){ return eventBus } }) new Vue({ render: h => h(App), }).$mount('#app')