想象一個(gè)場(chǎng)景,子組件依賴父組件傳遞的props,如果有多個(gè)這樣的props,其實(shí)已經(jīng)很煩了,當(dāng)有多個(gè)子組件,或者孫組件也依賴于由上至下的props時(shí),寫那么多props簡(jiǎn)直是要了親命了。
為了解決這種麻煩,產(chǎn)生了vuex。但是我們肯定希望組件的高可復(fù)用性,不引入vuex就能實(shí)現(xiàn)功能,那就要考慮vue本身是否支持這種能力了。熟悉React開發(fā)的人應(yīng)該會(huì)想到Context這個(gè)高階組件,它通過Provider和Consumer,可以使得無限嵌套的父子組件共有一個(gè)數(shù)據(jù)源。Vue也有一個(gè)類似的,連名字都很相似,就是這篇文章的主人公provide和inject。
依賴注入 ,官網(wǎng)有個(gè)例子,講述了為何我們需要 provide,它是可以終結(jié)復(fù)雜數(shù)據(jù)嵌套的神器。慣例先吹一波,不然寫這篇文章的意義沒了,=^^= 。閑話少說,上代碼。
// parent組件
<template>
<div>
<div>{{test}}</div>
<button @click="changeTest">修改test的值</button>
<son></son>
</div>
</template>
<script>
import Son from "./Son";
export default {
name: "parent",
components: { Son },
provide() {
return {
injectData: this.test
};
},
data() {
return {
test: "測(cè)試",
};
},
methods: {
changeTest() {
this.test = "測(cè)試后";
}
}
};
</script>
//son組件
<template>
<div>{{injectData}}</div>
</template>
<script>
export default {
name: "son",
inject: ["injectData"],
mounted() {
// eslint-disable-next-line
console.log(this.injectData)
},
};
</script>
parent組件使用provide提供一個(gè)injectData,son組件通過inject獲取到parent注入的數(shù)據(jù),以上就是它的最簡(jiǎn)用法。有一點(diǎn)需要注意,我們可以將inject得到的數(shù)據(jù)直接賦值給子組件的data或props,但是這個(gè)是在vue版本2.1之后才有的功能,這版本之前,會(huì)在data,props得到之后再得到注入的值。
使用provide/inject我們需要注意的是:
provide/inject這對(duì)選項(xiàng)需要一起使用,以允許一個(gè)祖先組件向其所有子孫后代注入一個(gè)依賴,不論組件層次有多深,并在起上下游關(guān)系成立的時(shí)間里始終生效。
provide 選項(xiàng)應(yīng)該是:一個(gè)對(duì)象或返回一個(gè)對(duì)象的函數(shù)
inject 選項(xiàng)應(yīng)該是:一個(gè)字符串?dāng)?shù)組,或 一個(gè)對(duì)象,對(duì)象的 key 是本地的綁定名
如果我們parent組件里provide是如下代碼:
provide: {
injectData: this.test
}
我們會(huì)發(fā)現(xiàn)this.test所得到的永遠(yuǎn)是undefined
provide: {
injectData:() => {
//eslint-disable-next-line
console.log(this)
}
},
我們打印出來的this永遠(yuǎn)是undefined,所以我們最好切記使用return返回一個(gè)對(duì)象,直接賦值對(duì)象僅在我們需要傳遞的是靜態(tài)數(shù)據(jù)時(shí)再使用。
最開始的例子測(cè)試中,我們會(huì)得到,provide傳遞的test數(shù)據(jù)并不是響應(yīng)式的,當(dāng)parent改變了test的值后,son組件無法得到改變后的值,這就產(chǎn)生了一個(gè)問題,我們肯定是希望父子組件拿到的數(shù)據(jù)是相同的。

我們先看看官網(wǎng)是如何說的,哦,并不直接是可響應(yīng)的,而是要我們?nèi)藶槭顾强身憫?yīng)的,之前的測(cè)試是符合的,因?yàn)槲覀?code>provide的只是一個(gè)字符串,可響應(yīng)的我們很快想到對(duì)象,數(shù)組這些。這樣又產(chǎn)生一個(gè)問題,是provide傳遞的值就必須是個(gè)對(duì)象,還是說,傳遞的可以是個(gè)指針,指向的是個(gè)對(duì)象呢?實(shí)踐出真知,測(cè)試一下。
provide() {
return {
injectData: this.test
};
},
data() {
return {
test: {
test: "測(cè)試"
},
};
},
我們先將provide的改成上面的,結(jié)果是響應(yīng)式的,我們?cè)贉y(cè)試一下另外一種。
provide() {
return {
injectData: {
test: this.test
}
};
},
data() {
return {
test: "測(cè)試"
};
},
測(cè)試得出結(jié)果,上面的不是響應(yīng)式的。事實(shí)證明,必須是inject能拿到的數(shù)據(jù)對(duì)象響應(yīng)式,我們才能得到響應(yīng)式結(jié)果。
其實(shí)這樣也蠻麻煩的,比如如果父組件有超多需要傳遞下去的數(shù)據(jù),還有個(gè)超簡(jiǎn)潔的處理方式。
provide() {
return {
injectData: this
}
}
我們可以將父組件整個(gè)傳遞到所需組件中去,并且組件實(shí)例本身就是響應(yīng)式的,這樣足以滿足我們大部分組件需求。
使用時(shí),我這邊還是遇到了一種場(chǎng)景,不是provide的問題,但是與之有點(diǎn)關(guān)系。當(dāng)我們將組件實(shí)例注入之后,子組件是能拿到組件的所有數(shù)據(jù)的,但是當(dāng)父組件內(nèi)里數(shù)據(jù)改變時(shí),子組件是監(jiān)聽不到數(shù)據(jù)的變化的,頁面也無法刷新,我是取了個(gè)巧,對(duì)數(shù)組進(jìn)行 splice或者concat等其他會(huì)觸發(fā)數(shù)組更新監(jiān)聽的操作,對(duì)象的話可以使用...或Object.assign。$set沒什么用 ==!響應(yīng)式更新機(jī)制,還是有很多不便的地方,刷新的解決方式還有待商榷,希望有更好的方法。