vue3中引入新的組件傳值方式,就是provide/inject依賴注入模式,在vue、react、angular三個熱門前端框架中,angular是最早用到了。當然依賴注入的這種概念最早是源于后端,再次感嘆下現(xiàn)在的前端已經(jīng)不再是以前純粹的前端了,前端的發(fā)展受到越來越多后端技術(shù)的影響,各種花里胡哨的技術(shù)都要來前端這里試試,前端程序員表示學不動了哈哈哈哈。。。笑著笑著就哭了
廢話不多說了,進入正題
1.概念
它是vue提供的一種的新的組件之間的傳值方式,相比原來的props這種只能在父子組件中傳值的方式,provide/inject依賴注入更像是props的加強版,props只能父組件傳子組件,而依賴注入傳值可以由父組件傳給它的所有后代,以及后代的后代,無論隔著多遠,只要是它后代鏈上的子組件,值都能傳到,可以說很強大了。
有一個需要注意的點就是,它是父子組件這種向下穿透的傳值方式,所以兄弟組件之間傳值是不能用依賴注入的
下面講解依賴注入的用法,主要從兩個方面來講,第一種是在非setup函數(shù)里的用法,第二種在setup函數(shù)里的用法
2.不定義在setup函數(shù)里的一般用法
父組件提供provide
<script>
export default {
provide: {
user: '張三'
}
}
</script>
后代組件注入inject
<template>
<div>{{user}}</div>
</template>
<script>
export default {
inject: ['user']
}
</script>
provide值是對象的時候,在大括號里是不能用this的,會報錯,找不到值
<script>
export default {
data() {
return {
user:'張三'
}
},
provide: {
user: this.user // Uncaught TypeError: Cannot read properties of undefined (reading 'user')
}
}
</script>
如果希望使用父組件data里的變量來傳遞,這里有一種更通用的寫法,建議各位記住并采用這種寫法,忘掉上面那種
<script>
export default {
data() {
return {
user:'張三'
}
},
provide() {
return {
user:this.user // 這里的值即可以自定義內(nèi)容,也可以使用data里的變量值
}
}
}
</script>
這種寫法和data的函數(shù)式寫法是一樣的,這里只是provide端的寫法改變,inject注入的寫法還是跟上面的一樣。依賴注入是單向數(shù)據(jù)流的傳值方式,即只有從provide端改變數(shù)值才會改變inject端的數(shù)值,從inject端的改變數(shù)值不會影響到provide端的值
上面provide的這種賦值寫法,雖然可以引用到父組件的data變量,但是它不是響應(yīng)式的,如果user的值改變了,provide并不能檢測到,如果希望user值改變的同時能讓provide檢測到并同步更新到inject端,這里需要用到計算屬性
<script>
import { computed } from 'vue'
export default {
data() {
return {
user:'張三',
name: '法外狂徒'
}
},
provide() {
return {
user:computed(() => this.user),
name: computed(() => this.name) // 多條可以依次寫,互相之間不干擾
}
}
}
</script>
這樣就可以在user每次變更的時候通知到inject端了
3.定義在setup函數(shù)中的一般用法
vue3還引入了setup函數(shù),這也是個新東西,有了它以后,vue3差不多就有函數(shù)式編程內(nèi)味了,引入setup函數(shù)后,寫法上的改變還是很大的,這里我不展開講setup函數(shù),只講在setup函數(shù)里的依賴注入用法,依舊以第二點中的例子為例,只不過改成setup的寫法
父組件提供provide
<script>
import { provide, ref, reactive, readonly } from 'vue' // 需要引入provide
export default {
setup() {
const user = ref('張三') // 非引用類型的響應(yīng)式ref寫法
// const user = ref({name: '張三'}) // 引用類型的響應(yīng)式ref寫法 user.value.name調(diào)用
// const user = reactive({name: '張三'}) // 引用類型的響應(yīng)式reactive寫法, user.name調(diào)用
// const user = '張三' // 非響應(yīng)式寫法
provide('user', readonly(user)) // readonly是為了防止inject端修改數(shù)據(jù)影響到provide端
}
}
</script>
后代組件注入inject
<template>
<div>{{user}}</div>
</template>
<script>
import { inject } from 'vue'
export default {
setup() {
const user = inject('user')
return { // 注意,在setup中定義的值需要return出去才能在子組件中直接使用
user
}
}
}
</script>
setup函數(shù)里的依賴注入用法有挺多要注意的地方,我都寫在代碼注釋里了
還需要解釋的一點是,setup函數(shù)中不要使用this,因為setup的調(diào)用在data、computed、methods之前,所以用this是取不到組件的變量的
4.依賴注入在實際開發(fā)中的一些情況
1.上述2種依賴注入寫法混合搭配也能正常傳值和取值,例如provide端用setup寫法,inject端用正常寫法;或者provide端用正常寫法,inject端用setup寫法都是可以的,但是不建議實際開發(fā)中這樣做
2.同一個組件中,存在setup寫法的provide和正常寫法的provide時,兩個provide傳的值會共存。
但是如果2個provide共同傳了一個key相同,但value不同的值,則最終inject端只能接收到正常provide寫法傳來的值。
對于這個現(xiàn)象,我一開始以為是正常寫法的provide的優(yōu)先級高于setup寫法的provide,到后來想想還存在一種可能性,就是setup寫法傳的值有可能是被正常寫法覆蓋了。因沒有去看源碼,所以具體是什么原因也不知道,以上只是猜測
最后
setup的知識點非常多,如果上述setup的依賴注入例子沒有看懂的話,建議去官網(wǎng)看下setup相關(guān)的內(nèi)容先
https://v3.cn.vuejs.org/guide/composition-api-setup.html setup函數(shù)
https://v3.cn.vuejs.org/guide/composition-api-provide-inject.html setup函數(shù)里的依賴注入