Vue中provide、inject詳解以及使用教程
- 傳送門:Vue中 子組件向父組件傳值 及 .sync 修飾符 詳解
- 傳送門:Vue中 狀態(tài)管理器(vuex)詳解及應(yīng)用場(chǎng)景
- 傳送門:Vue中 $ attrs、$ listeners 詳解及使用
- 傳送門:Vue中 事件總線(eventBus)詳解及使用
- 傳送門:Vue 2.x 官方文檔 provide / inject 說(shuō)明
Vue中 常見的組件通信方式可分為三類
父子通信
父向子傳遞數(shù)據(jù)是通過(guò) props,子向父是通過(guò) events($emit);
通過(guò)父鏈 / 子鏈也可以通信($parent / $children);
ref 也可以訪問(wèn)組件實(shí)例;
provide / inject;
$attrs/$listeners;
兄弟通信
Bus;
Vuex;
跨級(jí)通信
Bus;
Vuex;
provide / inject、
$attrs / $listeners、
1. provide / inject 簡(jiǎn)介
類型
provide:Object | () => Object inject: Array<string> | { [key: string]: string | Symbol | Object }
詳細(xì)
這對(duì)選項(xiàng)需要一起使用,以允許一個(gè)祖先組件向其所有子孫后代注入一個(gè)依賴,不論組件層次有多深,并在其上下游關(guān)系成立的時(shí)間里始終生效。
如果你熟悉 React,這與 React 的上下文特性很相似。provide 選項(xiàng)應(yīng)該是一個(gè)對(duì)象或返回一個(gè)對(duì)象的函數(shù)。該對(duì)象包含可注入其子孫的 property。
在該對(duì)象中可使用 ES2015 Symbols 作為 key,但是只在原生支持 Symbol 和 Reflect.ownKeys 的環(huán)境下可工作。inject 選項(xiàng)應(yīng)該是:
一個(gè)字符串?dāng)?shù)組,或
一個(gè)對(duì)象,對(duì)象的 key 是本地的綁定名,value 是:
在可用的注入內(nèi)容中搜索用的 key (字符串或 Symbol),或
一個(gè)對(duì)象,該對(duì)象的:
from property 是在可用的注入內(nèi)容中搜索用的 key (字符串或 Symbol)
default property 是降級(jí)情況下使用的 value
2. provide / inject 使用方法
祖組件
<template> <div> <button @click="changeMsg">祖組件觸發(fā)</button> <h1>祖組件</h1> <parent></parent> </div> </template> <script> import parent from './parent.vue'; export default { data(){ return{ obj:{ name:'JavaScript', }, developer:'布蘭登·艾奇', year:1995, update:'2021年06月', } }, provide(){ return { obj: this.obj, // 方式1.傳入一個(gè)可監(jiān)聽的對(duì)象 developerFn:() => this.developer, // 方式2.通過(guò) computed 來(lái)計(jì)算注入的值 year: this.year, // 方式3.直接傳值 app: this, // 4. 提供祖先組件的實(shí)例 缺點(diǎn):實(shí)例上掛載很多沒(méi)有必要的東西 比如:props,methods。 } }, components: { parent, }, methods:{ changeMsg(){ this.obj.name = 'Vue'; this.developer = '尤雨溪'; this.year = 2014; this.update = '2021年6月7日'; }, }, } </script>
父組件
<template> <div class="wrap"> <h4>子組件(只做中轉(zhuǎn))</h4> <child></child> </div> </template> <script> import child from './child.vue'; export default { components:{ child, }, } </script>
孫組件
<template> <div> <h5>孫組件</h5> <span>名稱:{{obj.name}}</span> | <span>作者:{{developer}}</span> | <span>誕生于:{{year}}</span> | <span>最后更新于:{{this.app.update}}</span> </div> </template> <script> export default { computed:{ developer(){ return this.developerFn() } }, inject:['obj','developerFn','year','app'], } </script>
未點(diǎn)擊按鈕,原有狀態(tài)
當(dāng)點(diǎn)擊按鈕觸發(fā) changeMsg 方法后,效果如下:
對(duì)比一下前后差異:無(wú)論點(diǎn)擊多少次,孫組件中的誕生于 year 字段永遠(yuǎn)都是1995 并不會(huì)發(fā)生變化,通過(guò) 方式1、方式2、方式4傳值是可以響應(yīng)的。
正是官網(wǎng)所提到的:provide 和 inject 綁定并不是可響應(yīng)的。這是刻意為之的。然而,如果你傳入了一個(gè)可監(jiān)聽的對(duì)象,那么其對(duì)象的 property 還是可響應(yīng)的。
在孫組件中修改祖組件傳遞過(guò)來(lái)的值(方式1、方式4),發(fā)現(xiàn)對(duì)應(yīng)的祖組件中的值也發(fā)生了變化。
祖組件
<template> <div> <h1>祖組件</h1> <span>名稱:{{obj.name}}</span> | <span>最后更新于:{{update}}</span> <parent></parent> </div> </template> <script> import parent from './parent.vue'; export default { data(){ return{ obj:{ name:'JavaScript', }, update:'2021年06月', } }, provide(){ return { obj: this.obj, app: this, } }, components: { parent, }, } </script>
父組件不變
孫組件
<template> <div> <button @click="changeMsg">孫組件觸發(fā)</button> <h3>孫組件</h3> <span>名稱:{{obj.name}}</span> | <span>最后更新于:{{this.app.update}}</span> </div> </template> <script> export default { inject:['obj','app'], methods: { changeMsg(){ this.obj.name = 'React'; this.app.update = '2020年10月'; } }, } </script>
未點(diǎn)擊按鈕,原有狀態(tài)
當(dāng)點(diǎn)擊按鈕觸發(fā) changeMsg 方法后,效果如下:
3. 總結(jié)
慎用 provide / inject
既然 provide/inject 如此好用,那么,為什么 Vue 官方還要推薦我們使用 Vuex,而不是用原生的 API 呢?
前面提到過(guò),Vuex 和 provide/inject 最大的區(qū)別:Vuex 中的全局狀態(tài)的每次修改是可以追蹤回溯的,而 provide/inject 中變量的修改是無(wú)法控制的。換句話說(shuō),不知道是哪個(gè)組件修改了這個(gè)全局狀態(tài)。
Vue 的設(shè)計(jì)理念借鑒了 React 中的單向數(shù)據(jù)流原則(雖然有 sync 這種破壞單向數(shù)據(jù)流的家伙),而 provide/inject 明顯破壞了單向數(shù)據(jù)流原則。試想,如果有多個(gè)后代組件同時(shí)依賴于一個(gè)祖先組件提供的狀態(tài),那么只要有一個(gè)組件修改了該狀態(tài),那么所有組件都會(huì)受到影響。這一方面增加了耦合度,另一方面,使得數(shù)據(jù)變化不可控。如果在多人協(xié)作開發(fā)中,這將成為一個(gè)噩夢(mèng)。
在這里,總結(jié)了使用 provide/inject 做全局狀態(tài)管理的原則:
- 多人協(xié)作時(shí),做好作用域隔離;
- 盡量使用一次性數(shù)據(jù)作為全局狀態(tài)
看起來(lái),使用 provide / inject 做全局狀態(tài)管理好像很危險(xiǎn),那么有沒(méi)有 provide / inject 更好的使用方式呢?
當(dāng)然有,那就是使用 provide / inject 編寫組件。
使用 provide / inject 編寫組件
使用 provide/inject 做組件開發(fā),是 Vue 官方文檔中提倡的一種做法。
以我們比較熟悉的 elementUI 來(lái)舉例:
在 elementUI 中有 Button(按鈕)組件,當(dāng)在 Form(表單)組件中使用時(shí),它的尺寸會(huì)同時(shí)受到外層的 FormItem 組件以及更外層的 Form 組件中的 size 屬性的影響。
如果是常規(guī)方案,我們可以通過(guò) props 從 Form 開始,一層層往下傳遞屬性值。看起來(lái)只需要傳遞傳遞兩層即可,還可以接受。但是,F(xiàn)orm 的下一層組件不一定是 FormItem,F(xiàn)ormItem 的下一層組件不一定是 Button,它們之間還可以嵌套其他組件,也就是說(shuō),層級(jí)關(guān)系不確定。如果使用 props,我們寫的組件會(huì)出現(xiàn)強(qiáng)耦合的情況。
provide/inject 可以完美的解決這個(gè)問(wèn)題,只需要向后代注入組件本身(上下文),后代組件中可以無(wú)視層級(jí)任意訪問(wèn)祖先組件中的狀態(tài)。
部分源碼如下:
export default { name: 'ElButton', // 通過(guò) inject 獲取 elForm 以及 elFormItem 這兩個(gè)組件 inject: { elForm: { default: '' }, elFormItem: { default: '' } }, // ... computed: { _elFormItemSize() { return (this.elFormItem || {}).elFormItemSize; }, buttonSize() { return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size; }, //... }, // ... };
總結(jié)
到此這篇關(guān)于Vue中provide、inject詳解及使用的文章就介紹到這了,更多相關(guān)Vue provide、inject詳解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue+django實(shí)現(xiàn)一對(duì)一聊天功能的實(shí)例代碼
這篇文章主要介紹了vue+django實(shí)現(xiàn)一對(duì)一聊天功能,主要是通過(guò)websocket,由于Django不支持websocket,所以我使用了django-channels。,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2019-07-07vue項(xiàng)目實(shí)現(xiàn)記住密碼到cookie功能示例(附源碼)
本篇文章主要介紹了vue項(xiàng)目實(shí)現(xiàn)記住密碼到cookie功能示例(附源碼),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01Vue封裝--如何將數(shù)字轉(zhuǎn)換成萬(wàn)
這篇文章主要介紹了Vue封裝--將數(shù)字轉(zhuǎn)換成萬(wàn)的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07vue 搭建后臺(tái)系統(tǒng)模塊化開發(fā)詳解
這篇文章主要介紹了vue 搭建后臺(tái)系統(tǒng)模塊化開發(fā)詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-05-05vue實(shí)現(xiàn)百度語(yǔ)音合成的實(shí)例講解
在本篇文章里小編給大家整理的是關(guān)于vue實(shí)現(xiàn)百度語(yǔ)音合成的實(shí)例內(nèi)容,以及相關(guān)代碼,需要的朋友們參考下。2019-10-10解決vue-router 嵌套路由沒(méi)反應(yīng)的問(wèn)題
這篇文章主要介紹了解決vue-router 嵌套路由沒(méi)反應(yīng)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09基于Vue3實(shí)現(xiàn)無(wú)限滾動(dòng)組件的示例代碼
如果你在社交媒體上停留的時(shí)間過(guò)長(zhǎng),那么,你所在的網(wǎng)站很可能正在使用無(wú)限滾動(dòng)組件。這篇文章教你利用Vue3實(shí)現(xiàn)無(wú)限滾動(dòng)組件,感興趣的可以參考一下2022-09-09Vue中引用assets中圖片的實(shí)現(xiàn)方式
這篇文章主要介紹了Vue中引用assets中圖片的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-10-10vue實(shí)現(xiàn)前臺(tái)列表數(shù)據(jù)過(guò)濾搜索、分頁(yè)效果
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)前臺(tái)列表數(shù)據(jù)過(guò)濾搜索、分頁(yè)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-05-05