背景
???????在父子組件傳遞數據時,通常使用的是 props 和 emit,父傳子時,使用的是 props,如果是父組件傳孫組件時,層層傳遞非常麻煩。
????????對于這種情況,我們可以使用一對 provide 和 inject。無論組件層次結構有多深,父組件都可以作為其所有子組件的依賴提供者。
????????這個特性有兩個部分:父組件有一個 provide 選項來提供數據,子組件有一個 inject 選項來開始使用這些數據。
vue2中的使用:
使用1: A->C 傳遞數據;
假設有一個組件A,A組件引入B組件(A為B的父組件)?,B組件引入C組件(B為C的父組件),即A為C的祖先組件,此時二者可以使用provide / inject進行通信。
-------------------------------- A 組件 ---------------------
<template><div><B></B></div>
</template><script>
import B from "./B.vue";
export default {name: "A",components: {B},provide:{name:"我是A提供的數據name", // 這種情況下,非響應式,可以寫成return的形式作為響應式},provide:{return {obj:this.obj,age:12,}}};
</script>
------------------------------ B 組件 ---------------------------
<template><div><C></C></div>
</template><script>
import C from "./C.vue";
export default {name: "B",components: {C},
};
</script>
-------------------------------C組件-------------------------------------
<template><div>{{name}} // 非響應式寫法{{obj.name}} // 響應式{{age}}</div>
</template><script>
export default {name: "C",inject:["name","obj","age"] // C組件在這里使用inject繼承和接受a的數據
};
</script>
此時A中的name改變,C中的值也會相應跟著變化。
使用2: C->A? 改變數據;
????????以上為A向C傳數據,如果C向A傳數據(或者說C需要改變A中的數據),該如何做?
我們這里不讓C直接改變A中的數據,而是將A改變數據的方法通過provide傳給C,C執行該方法,觸發改變A中的數據。
A使用provide傳入一個方法
<template><div><span>{{obj.name}}</span><B></B></div>
</template><script>
import B from "./B.vue";
export default {name: "A",components: {B},provide(){return {changeVal:this.changeName //傳入一個方法}},data(){return {obj:{name:"leo"}}},methods:{changeName(val){ //C中觸發該方法執行,此時變成"lion"this.obj.name = val}}
};
</script>
c使用inject 繼承該方法,在自己的方法內調取改方法即可
<template><div><span @click="changeName">點擊改變A組件數據</span></div>
</template><script>
export default {name: "C",inject:["changeVal"], //接收一個方法methods:{changeName(){this.changeVal("lion") //執行此方法,改變A中的數據}}
};
</script>
vue3 中的使用:
vue3:provide
在 setup() 中使用 provide 時,我們首先從 vue 顯式導入 provide 方法。這使我們能夠調用 provide 來定義每個 property。
provide 函數允許你通過兩個參數定義 property:
- name (<String> 類型)
- value
使用A組件,provide 的值可以按如下方式重構:
<template><C />
</template><script>
import { provide } from 'vue'
import C from './C.vue'export default {components: {C},setup() {provide('location', 'North Pole')provide('geolocation', {longitude: 90,latitude: 135})}
}
</script>
vue3: inject
在 setup() 中使用 inject 時,也需要從 vue 顯式導入。導入以后,我們就可以調用它來定義暴露給我們的組件方式。
inject 函數有兩個參數:
要 inject 的 property 的 name
默認值 (可選)
使用C組件,可以使用以下代碼對其進行重構:
<script>
import { inject } from 'vue'export default {setup() {const userLocation = inject('location', 'The Universe')const userGeolocation = inject('geolocation')return {userLocation,userGeolocation}}
}
</script>
provide響應式
為了增加 provide 值和 inject 值之間的響應性,我們可以在 provide 值時使用?ref?或?reactive。
<template><C />
</template><script>
import { provide, reactive, ref } from 'vue'
import C from './C.vue'export default {components: {C},setup() {const location = ref('North Pole')const geolocation = reactive({longitude: 90,latitude: 135})provide('location', location)provide('geolocation', geolocation)}
}
</script>
如果需要在c中修改a中的數據,需要向provide傳入一個方法
<template><C />
</template><script>
import { provide, reactive, ref } from 'vue'
import C from './C.vue'export default {components: {C},setup() {const location = ref('North Pole')const geolocation = reactive({longitude: 90,latitude: 135})const updateLocation = () => {location.value = 'South Pole'}provide('location', location)provide('geolocation', geolocation)provide('updateLocation', updateLocation) //傳入一個方法}
}
</script>
c中調用該方法
<script>
import { inject } from 'vue'export default {setup() {const userLocation = inject('location', 'The Universe')const userGeolocation = inject('geolocation')const updateUserLocation = inject('updateLocation')return {userLocation,userGeolocation,updateUserLocation //執行該方法,觸發祖先組件方法執行,從而改變數據}}
}
</script>
最后,如果要確保通過?provide
?傳遞的數據不會被 inject 的組件更改,我們建議對提供者的 property 使用?readonly
。
<template><C />
</template><script>
import { provide, reactive, readonly, ref } from 'vue'
import C from './C.vue'export default {components: {C},setup() {const location = ref('North Pole')const geolocation = reactive({longitude: 90,latitude: 135})const updateLocation = () => {location.value = 'South Pole'}// 使用readonly,數據只讀provide('location', readonly(location))provide('geolocation', readonly(geolocation))provide('updateLocation', updateLocation)}
}
</script>
? ? ? ? ? ? ? ? ? ? ? ??
參考文章:https://blog.csdn.net/qq_41809113/article/details/122071958