背景
在父子组件传递数据时,通常使用的是 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