在vue的學習中,vue組件間的通訊是不得不瞭解的,在實際開發中,也是很是經常使用的,因此這裏我總結了Vue組件的通訊的6種方式,但願能幫助小夥伴們更好更快的去理解Vue組件間的通訊前端
由上邊的圖能夠看出如下幾個關係:vue
由上邊幾個關係對下邊場景預覽:vuex
下面來爲你們詳細講解實現這些關係的幾種通訊方式跨域
props/$emit $parent / $children與 ref $emit/$on vuex $attrs/$listeners provide/inject
幾種組件通訊方法更好地選用markdown
當咱們的項目比較大時,能夠選擇更好的狀態管理解決方案vuex。 節制地使用$parent和$children,它們的主要目的是做爲訪問組件的應急方法, 更推薦用props和events實現父子組件通訊 若是僅僅是傳遞數據,就用$attrs/$listeners好點 如何不只傳遞數據,還作中間處理,就用vuex好些
下面經過一個例子來看父組件是如何向子組件傳遞數據的:
這個例子是子組件son.vue 經過 props 獲取 父組件father.vue 中的數據:
sonList: ['小白', '小紅', '小藍','小綠']app
<template> <div class="father"> <com-son :sons="sonList"></com-son> </div> </template> <script> import comSon from './son' export default { name: 'HelloWorld', components: { comSon }, data() { return { sonList: ['小白', '小紅', '小藍','小綠'] } } } </script>
<template> <div> <span v-for="(item, index) in sons" :key="index">{{item}}</span> </div> </template> <script> export default { props: ['sons'] } </script>
注意:異步
props 只能夠從上一級組件傳遞到下一級組件,也就是父子組件,即這就是單向數據流ide
props是隻讀,不能夠被修改,全部被修改都會失效和被警告函數
下面經過一個例子來看子組件是如何向父組件傳遞值:這個例子是子組件son.vue經過$emit向父組件值的傳遞學習
<template> <div class="father"> <com-son :sons="sonList" @onEmitIndex="onEmitIndex"></com-son> <p>{{currentIndex}}</p> </div> </template> <script> import comSon from './son' export default { name: 'HelloWorld', components: { comSon }, data() { return { currentIndex: -1, sonList: ['小白', '小紅', '小藍','小綠'] } }, methods:{ onEmitIndex(idx){ this.currentIndex = idx } } } </script>
<template> <div> <span v-for="(item, index) in sons" :key="index" @click="emitIndex(index)">{{item}}</span> </div> </template> <script> export default { props: ['sons'], methods: { emitIndex(index){ this.$emit('onEmitIndex',index) } } } </script>
在這裏我要說一下:
節制地使用$parent和$children,它們的主要目的是做爲訪問組件的應急方法, 更推薦用props和events實現父子組件通訊
下面咱們來經過一個實例說明$parent和$children的用法:
<template> <div class="father"> <com-son></com-son> <button @click="name">點擊改變子組件的值</button> </div> </template> <script> import comSon from './son' export default { name: 'HelloWorld', components: { comSon }, data() { return { msg: 'hello,早上好!' } }, methods:{ name(){ this.$children[0].message = "hello" } } } </script>
<template> <div class="com_a"> <span>{{message}}</span> <p>獲取父組件的值:{{parentVal}}</p> </div> </template> <script> export default { data(){ return { message:'Good wether' } }, computed:{ parentVal(){ return this.$parent.msg; } } } </script>
下邊再說ref訪問組件的例子:
export default { data () { return { title: 'Vue.js' } }, methods: { sayHello () { window.alert('Hello'); } } }
<template> <component-a ref="comA"></component-a> </template> <script> export default { mounted () { const comA = this.$refs.comA; console.log(comA.title); comA.sayHello(); } } </script>
注意:
這兩種方法的弊端,沒法在跨域兄弟間通訊
這個方法可用於父子、隔代、兄弟組件通訊
這種方式是經過一個相似App.vue的實例做爲一個模塊的事件中心,用它來觸發事件和監聽事件,從而實現任何組件間的通訊,包括父子、隔代、兄弟組件
當項目比較大的時候,能夠選擇更好的狀態管理解決方案vuex
下邊咱們來經過一個實例說明emit/on的用法:
在這裏先說一下:
有兩個組件A、B,在B組件中接收到A組件傳過來的數據
首先開闢個新的Vue根實例
而後咱們在A組件中經過$emit方式去定義一個自定義事件方法
而後經過$on去接收A組件自定義的事件傳過來的值
import Vue from 'vue' export default new Vue()
把組件A經過$emit傳到那個Vue空白實例裏面
<template> <div> <span>A組件->{{msg}}</span> <input type="button" value="把a組件數據傳給b" @click ="send"> </div> </template> <script> import vmson from "util/emptyVue" export default { data(){ return { msg:{ a:'666', b:'999' } } }, methods:{ send:function(){ vmson.$emit("aevent",this.msg) } } } </script>
組件B經過$on去監聽vmson實例中的自定義方法aevent
<template> <div> <span>{{msg}}</span> </div> </template> <script> import vmson from "util/emptyVue" export default { data(){ return { msg:"" } }, mounted(){ vmson.$on("aevent",(val)=>{//監聽aevent事件 console.log(val);//打印出來結果 this.msg = val; }) } } </script>
這個父組件就是把A、B兩個組件放在父組件中註冊渲染
<template> <div> <childa></childa> <childb></childb> </div> </template> <script> import childa from './childa.vue'; import childb from './childb.vue'; export default { components:{ childa, childb }, data(){ return { msg:"" } }, methods:{ } } </script>
Vuex是一個專爲Vue.js應用程序開發的狀態管理模式,它解決了組件之間同一狀態的共享問題,它採用集中式存儲管理應用的全部組件的狀態,因此組件就能夠和stort通信了,其實Vuex就是用來管理組件之間通訊的一個組件
假如不使用vuex
用了Vuex以後
state
state中存放頁面共享的狀態字段
getters
至關於當前模塊state的計算屬性
mutations
若是想更新state中的字段,提交mutations中定義的事件的惟一的方式 (key爲事件名,value是一個函數),可是中國事件函數必須是同步執行的
actions
能夠定義異步函數,並在回調中提交mutation,就至關於異步更新了state中的字段
modules
相似於命名空間,用於項目中將各個模塊的狀態分開定義和操做,便於維護
<template> <div id="app"> <ChildA/> <ChildB/> </div> </template> <script> import ChildA from 'components/ChildA' import ChildB from 'components/ChildB' export default { name: 'App', components: {ChildA, ChildB} } </script>
<template> <div id="childA"> <h1>我是A組件</h1> <button @click="transform">點我讓B組件接收到數據</button> <p>{BMessage}}</p> </div> </template> <script> export default { data() { return { AMessage: 'Hello,B組件,我是A組件' } }, computed: { BMessage() { return this.$store.state.BMsg } }, methods: { transform() { this.$store.commit('receiveAMsg', { AMsg: this.AMessage }) } } } </script>
<template> <div id="childB"> <h1>我是B組件</h1> <button @click="transform">點我看A組件接收的數據</button> <p>{{AMessage}}</p> </div> </template> <script> export default { data() { return { BMessage: 'Hello,A組件,我是B組件' } }, computed: { AMessage() { return this.$store.state.AMsg } }, methods: { transform() { this.$store.commit('receiveBMsg', { BMsg: this.BMessage }) } } } </script>
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const state = { // 初始化A和B組件的數據,等待獲取 AMsg: '', BMsg: '' } const mutations = { receiveAMsg(state, payload) { state.AMsg = payload.AMsg }, receiveBMsg(state, payload) { state.BMsg = payload.BMsg } } export default new Vuex.Store({ state, mutations })
用在父組件傳遞數據給子組件或者孫組件
若是僅僅是傳遞數據,就用$attrs/$listeners好點 如何不只傳遞數據,還作中間處理,就用vuex好些
$attrs:
$attrs繼承全部的父組件屬性(除了prop傳遞的屬性、class和style)
當一個組件沒有聲明任何 prop 時,這裏會包含全部父做用域的綁定 ( class 和 style 除外 ),而且能夠經過 v-bind="$attrs" 傳入內部組件。一般配合 inheritAttrs 選項一塊兒使用。
$listeners:
它是一個對象,包含了父做用域中的v-on事件監聽器,能夠配合v-on="$listeners"將全部的事件監聽器指向這個組件的某個特定的子元素
下面咱們來經過一個實例看$attrs/$listeners的用法:
例:假設有三個組件:A組件包含B組件,B組件包含C組件
<template> <div id="app"> <child1 :p-child1="child1" :p-child2="child2" v-on:test1="onTest1" v-on:test2="onTest2" //此處監聽了兩個事件,能夠在B組件或者C組件中直接觸發 > </child1> </div> </template> <script> import Child1 from './Child1.vue'; export default { data() { return {}; }, components: { Child1 }, methods: { onTest1() { console.log('test1 running...'); }, onTest2() { console.log('test2 running'); } } }; </script>
<template> <div class="child-1"> <p>in child1:</p> <p>props: {{pChild1}}</p> <p>$attrs: {{$attrs}}</p> <hr> <child2 v-bind="$attrs" v-on="$listeners"></child2> //v-on綁定了$listeners,因此C組件能直接觸發test //v-bind綁定了$attrs,因此C組件能夠獲取A組件傳遞下來的props的值 </div> </template> <script> import Child2 from './Child2.vue'; export default { props: ['pChild1'], data() { return {}; }, inheritAttrs: false, components: { Child2 }, mounted() { this.$emit('test1'); } }; </script>
<template> <div class="child-2"> <p>in child2:</p> <p>props: {{pChild2}}</p> <p>$attrs: {{$attrs}}</p> <hr> </div> </template> <script> export default { props: ['pChild2'], data() { return {}; }, inheritAttrs: false, mounted() { this.$emit('test2'); } }; </script>
祖先組件中經過provider來提供變量,而後在孫組件中經過inject來注入變量
procide/inject API主要解決了跨域組件間的通信問題,不過它的使用場景,主要是子組件獲取上級組件的狀態,跨級組件間創建了一種主動提供與依賴注入的關係
下邊經過一個例子來講明provide/inject的用法:
<template> <div> <son prop="data"></son> </div> </template> <script> export default { provide: { name: 'Tom' } }
這裏的孫子組件指的是:父組件、子組件、孫子組件
<template> <div> {{name}} </div> </template> <script> export default { name: 'grandson', inject: [name] } </script>
這裏能夠經過inject直接訪問其兩個層次以上的數據,
用法與props徹底相同
vue組件間的通信大體能夠分爲三類
props/emit、parent/children、 attrs/$listeners、provide/inject API、ref
父向子傳遞數據經過props 子向父傳遞是經過$emit、event 子實例訪問父實例經過$parent 父實例訪問子實例經過$children $attrs用父組件傳遞數據給子組件或孫組件 (包含了父做用域中不做爲 prop 被識別 (且獲取) 的特性綁定 (class 和 style 除外)) listeners用父組件傳遞數據給子組件或孫組件 包含了父做用域中的 (不含 .native 修飾器的) v-on 事件監聽器 祖先組件經過provider提供變量給子孫組件 子孫組件經過inject注入變量給祖先組件 ref用來訪問組件實例
Vuex
vuex用來做爲兄弟之間和跨級之間的通訊
Vuex、attrs/listeners、provide/inject API
vuex用來做爲兄弟之間和跨級之間的通訊 $attrs用父組件傳遞數據給子組件或孫組件 (包含了父做用域中不做爲 prop 被識別 (且獲取) 的特性綁定 (class 和 style 除外)) listeners用父組件傳遞數據給子組件或孫組件 包含了父做用域中的 (不含 .native 修飾器的) v-on 事件監聽器 祖先組件經過provider提供變量給子孫組件 子孫組件經過inject注入變量給祖先組件
若是本文對你有幫助得話,給本文點個贊❤️❤️❤️
歡迎你們加入,一塊兒學習前端,共同進步!