Vue中provide、inject詳解以及使用教程
- 傳送門:Vue中 子組件向父組件傳值 及 .sync 修飾符 詳解
- 傳送門:Vue中 狀態(tài)管理器(vuex)詳解及應(yīng)用場景
- 傳送門:Vue中 $ attrs、$ listeners 詳解及使用
- 傳送門:Vue中 事件總線(eventBus)詳解及使用
- 傳送門:Vue 2.x 官方文檔 provide / inject 說明
Vue中 常見的組件通信方式可分為三類
父子通信
父向子傳遞數(shù)據(jù)是通過 props,子向父是通過 events($emit);
通過父鏈 / 子鏈也可以通信($parent / $children);
ref 也可以訪問組件實(shí)例;
provide / inject;
$attrs/$listeners;
兄弟通信
Bus;
Vuex;
跨級通信
Bus;
Vuex;
provide / inject、
$attrs / $listeners、
1. provide / inject 簡介
類型
provide:Object | () => Object
inject: Array<string> | { [key: string]: string | Symbol | Object }
詳細(xì)
這對選項(xiàng)需要一起使用,以允許一個(gè)祖先組件向其所有子孫后代注入一個(gè)依賴,不論組件層次有多深,并在其上下游關(guān)系成立的時(shí)間里始終生效。
如果你熟悉 React,這與 React 的上下文特性很相似。provide 選項(xiàng)應(yīng)該是一個(gè)對象或返回一個(gè)對象的函數(shù)。該對象包含可注入其子孫的 property。
在該對象中可使用 ES2015 Symbols 作為 key,但是只在原生支持 Symbol 和 Reflect.ownKeys 的環(huán)境下可工作。inject 選項(xiàng)應(yīng)該是:
一個(gè)字符串?dāng)?shù)組,或
一個(gè)對象,對象的 key 是本地的綁定名,value 是:
在可用的注入內(nèi)容中搜索用的 key (字符串或 Symbol),或
一個(gè)對象,該對象的:
from property 是在可用的注入內(nèi)容中搜索用的 key (字符串或 Symbol)
default property 是降級情況下使用的 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)聽的對象
developerFn:() => this.developer, // 方式2.通過 computed 來計(jì)算注入的值
year: this.year, // 方式3.直接傳值
app: this, // 4. 提供祖先組件的實(shí)例 缺點(diǎn):實(shí)例上掛載很多沒有必要的東西 比如: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 方法后,效果如下:

對比一下前后差異:無論點(diǎn)擊多少次,孫組件中的誕生于 year 字段永遠(yuǎn)都是1995 并不會(huì)發(fā)生變化,通過 方式1、方式2、方式4傳值是可以響應(yīng)的。
正是官網(wǎng)所提到的:provide 和 inject 綁定并不是可響應(yīng)的。這是刻意為之的。然而,如果你傳入了一個(gè)可監(jiān)聽的對象,那么其對象的 property 還是可響應(yīng)的。
在孫組件中修改祖組件傳遞過來的值(方式1、方式4),發(fā)現(xiàn)對應(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 呢?
前面提到過,Vuex 和 provide/inject 最大的區(qū)別:Vuex 中的全局狀態(tài)的每次修改是可以追蹤回溯的,而 provide/inject 中變量的修改是無法控制的。換句話說,不知道是哪個(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è)噩夢。
在這里,總結(jié)了使用 provide/inject 做全局狀態(tài)管理的原則:
- 多人協(xié)作時(shí),做好作用域隔離;
- 盡量使用一次性數(shù)據(jù)作為全局狀態(tài)
看起來,使用 provide / inject 做全局狀態(tài)管理好像很危險(xiǎn),那么有沒有 provide / inject 更好的使用方式呢?
當(dāng)然有,那就是使用 provide / inject 編寫組件。
使用 provide / inject 編寫組件
使用 provide/inject 做組件開發(fā),是 Vue 官方文檔中提倡的一種做法。
以我們比較熟悉的 elementUI 來舉例:
在 elementUI 中有 Button(按鈕)組件,當(dāng)在 Form(表單)組件中使用時(shí),它的尺寸會(huì)同時(shí)受到外層的 FormItem 組件以及更外層的 Form 組件中的 size 屬性的影響。
如果是常規(guī)方案,我們可以通過 props 從 Form 開始,一層層往下傳遞屬性值??雌饋碇恍枰獋鬟f傳遞兩層即可,還可以接受。但是,F(xiàn)orm 的下一層組件不一定是 FormItem,F(xiàn)ormItem 的下一層組件不一定是 Button,它們之間還可以嵌套其他組件,也就是說,層級關(guān)系不確定。如果使用 props,我們寫的組件會(huì)出現(xiàn)強(qiáng)耦合的情況。
provide/inject 可以完美的解決這個(gè)問題,只需要向后代注入組件本身(上下文),后代組件中可以無視層級任意訪問祖先組件中的狀態(tài)。
部分源碼如下:
export default {
name: 'ElButton',
// 通過 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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
element日期時(shí)間選擇器限制時(shí)間選擇功能實(shí)現(xiàn)(精確到小時(shí))
文章介紹了如何使用Element UI的DateTimePicker組件來實(shí)現(xiàn)一個(gè)時(shí)間選擇器,該選擇器只能選擇當(dāng)前時(shí)間之后的7天,并且不能選擇當(dāng)前小時(shí),感興趣的朋友跟隨小編一起看看吧2025-01-01
Vue + Element-ui的下拉框el-select獲取額外參數(shù)詳解
這篇文章主要介紹了Vue + Element-ui的下拉框el-select獲取額外參數(shù)詳解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08
vue靜態(tài)配置文件不進(jìn)行編譯的處理過程(在public中引入js)
這篇文章主要介紹了vue靜態(tài)配置文件不進(jìn)行編譯的處理過程(在public中引入js),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
Vue數(shù)據(jù)更新頁面卻沒有更新的幾種情況以及解決方法
我們在開發(fā)過程中會(huì)碰到數(shù)據(jù)更新,但是頁面卻沒有更新的情況,下面這篇文章主要給大家介紹了關(guān)于Vue數(shù)據(jù)更新頁面卻沒有更新的幾種情況以及解決方法,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06
vue3中的reactive函數(shù)聲明數(shù)組方式
這篇文章主要介紹了vue3中的reactive函數(shù)聲明數(shù)組方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05
Vue 使用Props屬性實(shí)現(xiàn)父子組件的動(dòng)態(tài)傳值詳解
今天小編就為大家分享一篇Vue 使用Props屬性實(shí)現(xiàn)父子組件的動(dòng)態(tài)傳值詳解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11

