組件間的通訊是是實際開發中很是經常使用的一環,如何使用對項目總體設計、開發、規範都有很實際的的做用,我在項目開發中對此深有體會,總結下vue組件間通訊的幾種方式,討論下各自的使用場景php
文章對相關場景預覽vue
文章相關技術預覽
prop、emit、bus、vuex、路由URL、provide/inject、$attrs/inheritAttrsvuex
注:如下介紹與代碼環境:vue2.0+、vue-cli2vue-cli
父子組件的通訊是開發是最經常使用的也是最重要的,大家必定知道父子通訊是用prop傳遞數據的,像這樣:segmentfault
//父組件,傳遞數據 <editor :inputIndex="data" :inputName="王文健"></editor>
//子組件,接受數據,定義傳遞數據的類型type與默認值default props: { inputIndex: { type: Object, default: function(){ return {} } }, inputName: { type: String, default: '' },
注意項:api
父組件傳遞數據時相似在標籤中寫了一個屬性,若是是傳遞的數據是data中的天然是要在傳遞屬性前加v-bind:,若是傳遞的是一個已知的固定值呢數組
若是prop傳到子組件中的數據是一個對象的話,要注意傳遞的是一個對象引用,雖然父子組件看似是分離的但最後都是在同一對象下session
在vue中子向父傳遞數據通常用$emit自定義事件,在父組件中監聽這個事件並在回調中寫相關邏輯dom
// 父組件監聽子組件定義的事件 <editor :inputIndex="index" @editorEmit='editorEmit'></editor>
// 子組件須要返回數據時執行,並能夠傳遞數據 this.$emit('editorEmit', data)
那麼問題來了,我是否是真的有必要去向父組件返回這個數據,用自定義事件能夠在當子組件想傳遞數據或向子組件傳遞的數據有變化須要從新傳遞時執行,那麼另一種場景,父組件須要子組件的一個數據但子組件並不知道或者說沒有能力在父組件想要的時候給父組件,那麼這個時候就要用到組件的一個選項ref:ide
<editor ref="editor" @editorEmit='editorEmit'></editor>
vue中兄弟組件間的通訊是很不方便的,或者說不支持的,那麼父子組件中都有什麼通訊方式呢
路由URL參數
在傳統開發時咱們經常把須要跨頁面傳遞的數據放到url後面,跳轉到另外頁面時直接獲取url字符串獲取想要的參數便可,在vue跨組件時同樣能夠這麼作,
``` // router index.js 動態路由 { path:'/params/:Id', component:Params, name:Params } ``` ``` // 跳轉路由 <router-link :to="/params/12">跳轉路由</router-link> ```在組件以外定義一個bus.js做爲組件間通訊的橋樑,適用於比較小型不須要vuex又須要兄弟組件通訊的
bus.js中添加以下
``` import Vue from 'vue' export default new Vue ```組件中調用bus.js經過自定義事件傳遞數據
``` import Bus from './bus.js' export default { methods: { bus () { Bus.$emit('msg', '我要傳給兄弟組件們') } } } ```兄弟組件中監聽事件接受數據
``` import Bus from './bus.js' export default { mounted() { Bus.$on('msg', (e) => { console.log(e) }) } } ```注:以上兩種使用場景並不高因此只是簡略提一下,這兩點都是好久之前寫過,以上例子網上直接蒐集而來若有錯誤,指正
vuex是vue的集中狀態管理工具,對於大型應用統一集中管理數據,很方便,在此對vuex的用法並不過多介紹只是提一下使用過程當中遇到的問題
規範:對於多人開發的大型應用規範的制定是相當重要的,對於全部人都會接觸到的vuex對其修改數據調用數據都應有一個明確嚴格的使用規範
provide/inject
除了正常的父子組件傳值外,vue也提供了provide/inject
這對選項須要一塊兒使用,以容許一個祖先組件向其全部子孫後代注入一個依賴,不論組件層次有多深,並在起上下游關係成立的時間裏始終生效
官網實例
// 父級組件提供 'foo' var Provider = { provide: { foo: 'bar' }, // ... } // 子組件注入 'foo' var Child = { inject: ['foo'], created () { console.log(this.foo) // => "bar" } }
一個字符串數組,或
一個對象,對象的 key 是本地的綁定名,value 是:
在可用的注入內容中搜索用的 key (字符串或 Symbol),或
一個對象,該對象的:
提示:provide 和 inject 綁定並非可響應的。這是刻意爲之的。然而,若是你傳入了一個可監聽的對象,那麼其對象的屬性仍是可響應的。
具體細節移步vue相關介紹https://cn.vuejs.org/v2/api/#...
provide/inject還未在項目中應用過,後面會作嘗試
經小夥伴們提醒補充$attrs的使用
場景:祖先組件與子組件傳值
包含了父做用域中不做爲 prop 被識別 (且獲取) 的特性綁定 (class 和 style 除外)。當一個組件沒有聲明任何 prop 時,這裏會包含全部父做用域的綁定 (class 和 style 除外),而且能夠經過 v-bind="$attrs" 傳入內部組件——在建立高級別的組件時很是有用。
以上是官網對$attrs的解釋,我剛看我也是一臉懵逼,回去試了一下其實並不難,並且比較適用組件深層嵌套場景下,祖先組件向子組件傳值的問題
意思就是父組件傳向子組件傳的,子組件不prop接受的數據都會放在$attrs中,子組件直接用this.$attrs獲取就能夠了。如過從父->孫傳,就在子組件中添加v-bind='$attrs',就把父組件傳來的子組件沒props接收的數據所有傳到孫組件,具體看如下代碼
使用:
祖先組件
// 祖先組件 // 在祖先組件中直接傳入output和input <template> <div> <child1 :output='output' :input="input"></child1> </div> </template> <script> import child1 from './child1.vue' export default { components: { child1 }, data () { return { input: 'jijijijjijiji', output: { name: '王文健', age: '18' } } } </script>
子組件
<template> <div <h1>{{input}}</h1> <child2 :child="child" v-bind='$attrs'></child2> </div> </template> <script> import child2 from './child2.vue' export default { components: { child2 }, props: { input: [String] }, data () { return { child: 'child1child1child1child1s' } }, // 默認爲true,若是傳入的屬性子組件沒有prop接受,就會以字符串的形式出現爲標籤屬性 // 設爲false,在dom中就看不到這些屬性,試一下就知道了 inheritAttrs: false, created () { // 在子組件中打印的$attrs就是父組件傳入的值,刨去style,class,和子組件中已props的屬性 console.log(this.$attrs) // 打印output } } </script>
孫組件
<template> <div> {{$attrs.output.name}} </div> </template> <script> export default { created () { // 打印output和child console.log(this.$attrs) } } </script>
看起來仍是挺好用的,還沒在具體項目中用過,相信不久會用到的,若是還有什麼問題歡迎留言
$children/$parent
固然你能夠直接用$children/$parent獲取當前組件的子組件實例或父組件實例(若是有的話),也能對其作些操做,不過並不推薦這麼作
你還能夠放到localStorage,sessionStorage,cooikes之類的存在本地固然也能作到組件間的通訊
文章只是整理一下筆記,談一談遇到的問題和經驗,並無嚴謹的措辭和詳細的過程,若有錯誤望指正
原創文章轉載引用請註明原文連接http://blog.wwenj.com/index.p...
來源:https://segmentfault.com/a/1190000016627804