摘要:當(dāng)一個(gè)組件沒有聲明任何時(shí),這里會(huì)包含所有父作用域的綁定和除外,并且可以通過傳入內(nèi)部組件在創(chuàng)建高級(jí)別的組件時(shí)非常有用。
寫在前面
組件間的通信是是實(shí)際開發(fā)中非常常用的一環(huán),如何使用對(duì)項(xiàng)目整體設(shè)計(jì)、開發(fā)、規(guī)范都有很實(shí)際的的作用,我在項(xiàng)目開發(fā)中對(duì)此深有體會(huì),總結(jié)下vue組件間通信的幾種方式,討論下各自的使用場(chǎng)景
文章對(duì)相關(guān)場(chǎng)景預(yù)覽
父->子組件間的數(shù)據(jù)傳遞
子->父組件間的數(shù)據(jù)傳遞
兄弟組件間的數(shù)據(jù)傳遞
組件深層嵌套,祖先組件與子組件間的數(shù)據(jù)傳遞
文章相關(guān)技術(shù)預(yù)覽
prop、emit、bus、vuex、路由URL、provide/inject、$attrs/inheritAttrs
注:以下介紹與代碼環(huán)境:vue2.0+、vue-cli2
父->子組件間的數(shù)據(jù)傳遞父子組件的通信是開發(fā)是最常用的也是最重要的,你們一定知道父子通信是用prop傳遞數(shù)據(jù)的,像這樣:
//父組件,傳遞數(shù)據(jù)
//子組件,接受數(shù)據(jù),定義傳遞數(shù)據(jù)的類型type與默認(rèn)值default props: { inputIndex: { type: Object, default: function(){ return {} } }, inputName: { type: String, default: "" },
注意項(xiàng):
父組件傳遞數(shù)據(jù)時(shí)類似在標(biāo)簽中寫了一個(gè)屬性,如果是傳遞的數(shù)據(jù)是data中的自然是要在傳遞屬性前加v-bind:,如果傳遞的是一個(gè)已知的固定值呢
字符串是靜態(tài)的可直接傳入無(wú)需在屬性前加v-bind
數(shù)字,布爾,對(duì)象,數(shù)組,因?yàn)檫@些是js表達(dá)式而不是字符串,所以即使這些傳遞的是靜態(tài)的也需要加v-bind,把數(shù)據(jù)放到data中引用,
如果prop傳到子組件中的數(shù)據(jù)是一個(gè)對(duì)象的話,要注意傳遞的是一個(gè)對(duì)象引用,雖然父子組件看似是分離的但最后都是在同一對(duì)象下
如果prop傳到子組件的值只是作為初始值使用,且在父組件中不會(huì)變化賦值到data中使用
如果傳到子組件的prop的數(shù)據(jù)在父組件會(huì)被改變的,放到計(jì)算屬性中監(jiān)聽變化使用。因?yàn)槿绻麄鬟f的是個(gè)對(duì)象的話,只改變下面的某個(gè)屬性子組件中是不會(huì)響應(yīng)式更新的,如果子組件需要在數(shù)據(jù)變化時(shí)響應(yīng)式更新那只能放到computed中或者用watch深拷貝deep:true才能監(jiān)聽到變化
當(dāng)然如果你又需要在子組件中通過prop傳遞數(shù)據(jù)的變化做些操作,那么寫在computed中會(huì)報(bào)警告,因?yàn)橛?jì)算屬性中不推薦有任何數(shù)據(jù)的改變,最好只進(jìn)行計(jì)算。如果你非要進(jìn)行數(shù)據(jù)的操作那么可以把監(jiān)聽寫在watch(注意deep深拷貝)或者使用computed的get和set如下圖:
但問題又來(lái)了,如果你傳進(jìn)來(lái)的是個(gè)對(duì)象,同時(shí)你又需要在子組件中操作傳進(jìn)來(lái)的這個(gè)數(shù)據(jù),那么在父組件中的這個(gè)數(shù)據(jù)也會(huì)改變,因?yàn)槟銈鬟f的只是個(gè)引用, 即使你把prop的數(shù)據(jù)復(fù)制到data中也是一樣的,無(wú)論如何賦值都是引用的賦值,你只能對(duì)對(duì)象做深拷貝創(chuàng)建一個(gè)副本才能繼續(xù)操作,你可以用JSON的方法先轉(zhuǎn)化字符串在轉(zhuǎn)成對(duì)象更方便一點(diǎn),
所以在父子傳遞數(shù)據(jù)時(shí)要先考慮好數(shù)據(jù)要如何使用,否則你會(huì)遇到很多問題或子組件中修改了父組件中的數(shù)據(jù),這是很隱蔽并且很危險(xiǎn)的
子->父組件間的數(shù)據(jù)傳遞在vue中子向父?jìng)鬟f數(shù)據(jù)一般用$emit自定義事件,在父組件中監(jiān)聽這個(gè)事件并在回調(diào)中寫相關(guān)邏輯
// 父組件監(jiān)聽子組件定義的事件
// 子組件需要返回?cái)?shù)據(jù)時(shí)執(zhí)行,并可以傳遞數(shù)據(jù) this.$emit("editorEmit", data)
那么問題來(lái)了,我是不是真的有必要去向父組件返回這個(gè)數(shù)據(jù),用自定義事件可以在當(dāng)子組件想傳遞數(shù)據(jù)或向子組件傳遞的數(shù)據(jù)有變化需要重新傳遞時(shí)執(zhí)行,那么另外一種場(chǎng)景,父組件需要子組件的一個(gè)數(shù)據(jù)但子組件并不知道或者說沒有能力在父組件想要的時(shí)候給父組件,那么這個(gè)時(shí)候就要用到組件的一個(gè)選項(xiàng)ref:
父組件在標(biāo)簽中定義ref屬性,在js中直接調(diào)用this.$refs.editor就是調(diào)用整個(gè)子組件,子組件的所有內(nèi)容都能通過ref去調(diào)用,當(dāng)然我們并不推薦因?yàn)檫@會(huì)使數(shù)據(jù)看起來(lái)非常混亂,
所以我們可以在子組件中定義一種專供父組件調(diào)用的函數(shù),,比如我們?cè)谶@個(gè)函數(shù)中返回子組件data中某個(gè)數(shù)據(jù),當(dāng)父組件想要獲取這個(gè)數(shù)據(jù)就直接主動(dòng)調(diào)用ref執(zhí)行這個(gè)函數(shù)獲取這個(gè)數(shù)據(jù),這樣能適應(yīng)很大一部分場(chǎng)景,邏輯也更清晰一點(diǎn)
另外,父向子傳遞數(shù)據(jù)也可以用ref,有次需要在一個(gè)父組件中大量調(diào)用同一個(gè)子組件,而每次調(diào)用傳遞的prop數(shù)據(jù)都不同,并且傳遞數(shù)據(jù)會(huì)根據(jù)之后操作變化,這樣我需要在data中定義大量相關(guān)數(shù)據(jù)并改變它,我可以直接用ref調(diào)用子組件函數(shù)直接把數(shù)據(jù)以參數(shù)的形式傳給子組件,邏輯一下子清晰了
如果調(diào)用基礎(chǔ)組件可以在父組件中調(diào)用ref執(zhí)行基礎(chǔ)組件中暴露的各種功能接口,比如顯示,消失等
兄弟組件間的數(shù)據(jù)傳遞vue中兄弟組件間的通信是很不方便的,或者說不支持的,那么父子組件中都有什么通信方式呢
路由URL參數(shù)
在傳統(tǒng)開發(fā)時(shí)我們常常把需要跨頁(yè)面?zhèn)鬟f的數(shù)據(jù)放到url后面,跳轉(zhuǎn)到另外頁(yè)面時(shí)直接獲取url字符串獲取想要的參數(shù)即可,在vue跨組件時(shí)一樣可以這么做,
// router index.js 動(dòng)態(tài)路由 { path:"/params/:Id", component:Params, name:Params }
// 跳轉(zhuǎn)路由跳轉(zhuǎn)路由
在跳轉(zhuǎn)后的組件中用$route.params.id去獲取到這個(gè)id參數(shù)為12,但這種只適合傳遞比較小的數(shù)據(jù),數(shù)字之類的
Bus通信
在組件之外定義一個(gè)bus.js作為組件間通信的橋梁,適用于比較小型不需要vuex又需要兄弟組件通信的
bus.js中添加如下
import Vue from "vue" export default new Vue
組件中調(diào)用bus.js通過自定義事件傳遞數(shù)據(jù)
import Bus from "./bus.js" export default { methods: { bus () { Bus.$emit("msg", "我要傳給兄弟組件們") } } }
兄弟組件中監(jiān)聽事件接受數(shù)據(jù)
import Bus from "./bus.js" export default { mounted() { Bus.$on("msg", (e) => { console.log(e) }) } }
注:以上兩種使用場(chǎng)景并不高所以只是簡(jiǎn)略提一下,這兩點(diǎn)都是很久以前寫過,以上例子網(wǎng)上直接搜集而來(lái)如有錯(cuò)誤,指正
Vuex集中狀態(tài)管理
vuex是vue的集中狀態(tài)管理工具,對(duì)于大型應(yīng)用統(tǒng)一集中管理數(shù)據(jù),很方便,在此對(duì)vuex的用法并不過多介紹只是提一下使用過程中遇到的問題
規(guī)范:對(duì)于多人開發(fā)的大型應(yīng)用規(guī)范的制定是至關(guān)重要的,對(duì)于所有人都會(huì)接觸到的vuex對(duì)其修改數(shù)據(jù)調(diào)用數(shù)據(jù)都應(yīng)有一個(gè)明確嚴(yán)格的使用規(guī)范
vuex分模塊:項(xiàng)目不同模塊間維護(hù)各自的vuex數(shù)據(jù)
限制調(diào)用:只允許action操作數(shù)據(jù),getters獲取數(shù)據(jù),使用mapGetters,mapActions輔助函數(shù)調(diào)用數(shù)據(jù)
對(duì)于vuex的使用場(chǎng)景也有一些爭(zhēng)論,有人認(rèn)為正常組件之間就是要用父子組件傳值的方式,即使子組件需要使vuex中的數(shù)據(jù)也應(yīng)該由父組件獲取再傳到子組件中,但有的時(shí)候組件間嵌套很深,只允許父組件獲取數(shù)據(jù)并不是一個(gè)方便的方法,所以對(duì)于祖先元組件與子組件傳值又有了新問題,vue官網(wǎng)也有一些方法解決,如下
祖先組件與子組件間的數(shù)據(jù)傳遞provide/inject
除了正常的父子組件傳值外,vue也提供了provide/inject
這對(duì)選項(xiàng)需要一起使用,以允許一個(gè)祖先組件向其所有子孫后代注入一個(gè)依賴,不論組件層次有多深,并在起上下游關(guān)系成立的時(shí)間里始終生效
官網(wǎng)實(shí)例
// 父級(jí)組件提供 "foo" var Provider = { provide: { foo: "bar" }, // ... } // 子組件注入 "foo" var Child = { inject: ["foo"], created () { console.log(this.foo) // => "bar" } }
provide 選項(xiàng)應(yīng)該是一個(gè)對(duì)象或返回一個(gè)對(duì)象的函數(shù)。該對(duì)象包含可注入其子孫的屬性。
一個(gè)字符串?dāng)?shù)組,或
一個(gè)對(duì)象,對(duì)象的 key 是本地的綁定名,value 是:
在可用的注入內(nèi)容中搜索用的 key (字符串或 Symbol),或
一個(gè)對(duì)象,該對(duì)象的:
from 屬性是在可用的注入內(nèi)容中搜索用的 key (字符串或 Symbol)
default 屬性是降級(jí)情況下使用的 value
提示:provide 和 inject 綁定并不是可響應(yīng)的。這是刻意為之的。然而,如果你傳入了一個(gè)可監(jiān)聽的對(duì)象,那么其對(duì)象的屬性還是可響應(yīng)的。
具體細(xì)節(jié)移步vue相關(guān)介紹https://cn.vuejs.org/v2/api/#...
provide/inject還未在項(xiàng)目中應(yīng)用過,后面會(huì)做嘗試
補(bǔ)充 $attrs/inheritAttrs經(jīng)小伙伴們提醒補(bǔ)充$attrs的使用
場(chǎng)景:祖先組件與子組件傳值
如果是props的話,就必須在子組件與祖先組件之間每個(gè)組件都要prop接受這個(gè)數(shù)據(jù),再傳到下一層子組件,這就很麻煩,耦合深程序臃腫
如果用vuex確實(shí)顯得有點(diǎn)小題大做了,所以用$attrs直接去獲取祖先數(shù)據(jù)也不錯(cuò)
包含了父作用域中不作為 prop 被識(shí)別 (且獲取) 的特性綁定 (class 和 style 除外)。當(dāng)一個(gè)組件沒有聲明任何 prop 時(shí),這里會(huì)包含所有父作用域的綁定 (class 和 style 除外),并且可以通過 v-bind="$attrs" 傳入內(nèi)部組件——在創(chuàng)建高級(jí)別的組件時(shí)非常有用。
以上是官網(wǎng)對(duì)$attrs的解釋,我剛看我也是一臉懵逼,回去試了一下其實(shí)并不難,而且比較適用組件深層嵌套場(chǎng)景下,祖先組件向子組件傳值的問題
意思就是父組件傳向子組件傳的,子組件不prop接受的數(shù)據(jù)都會(huì)放在$attrs中,子組件直接用this.$attrs獲取就可以了。如過從父->孫傳,就在子組件中添加v-bind="$attrs",就把父組件傳來(lái)的子組件沒props接收的數(shù)據(jù)全部傳到孫組件,具體看以下代碼
使用:
祖先組件
// 祖先組件 // 在祖先組件中直接傳入output和input
子組件
{{input}}
孫組件
{{$attrs.output.name}}
看起來(lái)還是挺好用的,還沒在具體項(xiàng)目中用過,相信不久會(huì)用到的,如果還有什么問題歡迎留言
$children/$parent
當(dāng)然你可以直接用$children/$parent獲取當(dāng)前組件的子組件實(shí)例或父組件實(shí)例(如果有的話),也能對(duì)其做些操作,不過并不推薦這么做
你還可以放到localStorage,sessionStorage,cooikes之類的存在本地當(dāng)然也能做到組件間的通信
文章只是整理一下筆記,談一談?dòng)龅降膯栴}和經(jīng)驗(yàn),并沒有嚴(yán)謹(jǐn)?shù)拇朕o和詳細(xì)的過程,如有錯(cuò)誤望指正
原創(chuàng)文章轉(zhuǎn)載引用請(qǐng)注明原文鏈接http://blog.wwenj.com/index.p...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/98231.html
摘要:本文總結(jié)了組件間通信的幾種方式,如和,以通俗易懂的實(shí)例講述這其中的差別及使用場(chǎng)景,希望對(duì)小伙伴有些許幫助。狀態(tài)改變提交操作方法。 前言 組件是 vue.js最強(qiáng)大的功能之一,而組件實(shí)例的作用域是相互獨(dú)立的,這就意味著不同組件之間的數(shù)據(jù)無(wú)法相互引用。一般來(lái)說,組件可以有以下幾種關(guān)系:showImg(https://segmentfault.com/img/remote/146000001...
摘要:本文總結(jié)了組件間通信的幾種方式,如和,以通俗易懂的實(shí)例講述這其中的差別及使用場(chǎng)景,希望對(duì)小伙伴有些許幫助。狀態(tài)改變提交操作方法。前言 組件是 vue.js最強(qiáng)大的功能之一,而組件實(shí)例的作用域是相互獨(dú)立的,這就意味著不同組件之間的數(shù)據(jù)無(wú)法相互引用。一般來(lái)說,組件可以有以下幾種關(guān)系: showImg(https://user-gold-cdn.xitu.io/2019/5/17/16ac35bf...
摘要:上圖是二月份前端框架排名,位居第一,排名第三。我們認(rèn)為前端模板和組件代碼是緊密相連的。直到最近看了文檔,才發(fā)現(xiàn)另有蹊蹺。 歡迎大家關(guān)注騰訊云技術(shù)社區(qū)-segmentfault官方主頁(yè),我們將持續(xù)在博客園為大家推薦技術(shù)精品文章哦~ 紀(jì)俊,從事Web前端開發(fā)工作,2016年加入騰訊OMG廣告平臺(tái)產(chǎn)品部,喜歡研究前端技術(shù)框架。 這里要討論的話題,不是前端框架哪家強(qiáng),因?yàn)樵?Vue 官網(wǎng)就已經(jīng)...
平日學(xué)習(xí)接觸過的網(wǎng)站積累,以每月的形式發(fā)布。2017年以前看這個(gè)網(wǎng)址:http://www.kancloud.cn/jsfron... 03月份前端資源分享 1. Javascript 175453545 Redux compose and middleware 源碼分析 深入 Promise(二)——進(jìn)擊的 Promise Effective JavaScript leeheys blog -...
平日學(xué)習(xí)接觸過的網(wǎng)站積累,以每月的形式發(fā)布。2017年以前看這個(gè)網(wǎng)址:http://www.kancloud.cn/jsfron... 03月份前端資源分享 1. Javascript 175453545 Redux compose and middleware 源碼分析 深入 Promise(二)——進(jìn)擊的 Promise Effective JavaScript leeheys blog -...
閱讀 1829·2021-09-14 18:03
閱讀 2267·2019-08-30 15:48
閱讀 1121·2019-08-30 14:09
閱讀 507·2019-08-30 12:55
閱讀 2724·2019-08-29 11:29
閱讀 1483·2019-08-26 13:43
閱讀 2311·2019-08-26 13:30
閱讀 2369·2019-08-26 12:17