组件之间的多层传值我们前面学习过了通过$attrs和$listeners,今天我们来学习一个更为简单的方法利用组件对象的属性provide和inject,它们与data、methods这些属于同级。
用法:在需要提供数据的组件内设置provide,其设置的属性值为对象或者为函数的返回值对象;在需要获取数据的组件内直接用inject注入到当前组件中,不管你处于那一层都能够获取到,inject属性的值为一个字符串数组,或一个对象,对象的情况可具体查看官方API。
用三个组件演示一下:爷爷组件、父亲组件、孙子组件
爷爷组件:提供数据
<template>
<div class="app">
<div>{{msg}}</div>
<Box1></Box1>
</div>
</template>
<script>
import Box1 from "@/components/box1.vue"
export default {
data() {
return {
msg:"爷爷组件的数据"
}
},
provide:function(){
return {
msg:this.msg
}
},
components:{
Box1
},
}
</script>
<style>
.app{
width: 300px;
height: 300px;
background-color: aquamarine;
}
</style>
父亲组件:可以被注入提供的数据
<template>
<div class="box1">
<h2>box1组件</h2>
<div>{{msg}}</div>
<Box2></Box2>
</div>
</template>
<script>
import Box2 from "./box2.vue"
export default{
components:{
Box2
},
inject:["msg"]
}
</script>
<style>
.box1{
width: 150px;
height: 150px;
background-color: aqua;
}
</style>
孙子组件:也可以获取数据
<template>
<div class="box2">
<h3>box3组件</h3>
<div> {{msg}}</div>
</div>
</template>
<script>
export default{
inject:["msg"]
}
</script>
<style>
.box2{
width: 100px;
height:100px;
background-color: yellow;
}
</style>
页面效果:
但是它有一个缺点就是数据不是响应式的,如我在爷爷组件方法内修改提供的值,但是子组件中获取的值不会改变。
演示一下,修改爷爷组件的代码:
<template>
<div class="app">
<div>{{msg}}</div>
<button v-on:click="change">修改msg</button>
<Box1></Box1>
</div>
</template>
<script>
import Box1 from "@/components/box1.vue"
export default {
data() {
return {
msg:"爷爷组件的数据"
}
},
methods: {
change(){
this.msg="修改了"
}
},
// provide:{msg:this.msg}
provide:function(){
return {
msg:this.msg
}
},
components:{
Box1
},
}
</script>
<style>
.app{
width: 300px;
height: 300px;
background-color: aquamarine;
}
</style>
当我们点击按钮修改了msg后,只有父组件内页面数据发生了变化,效果:
解决办法:提供的数据变成一个对象如provide:{msg:{...}},因为对象是一种引用数据,它在内存开辟了一块内存空间。被注入的的组件引用也是指向这块地址,所以能够改变。
再修改代码:
<template>
<div class="app">
<div>{{msg}}</div>
<button v-on:click="change">修改msg</button>
<Box1></Box1>
</div>
</template>
<script>
import Box1 from "@/components/box1.vue"
export default {
data() {
return {
msg:{msg:"对象形式传入"}
}
},
methods: {
change(){
this.msg="修改了"
}
},
// provide:{msg:this.msg}
provide:function(){
return {
msg:this.msg
}
},
components:{
Box1
},
}
</script>
<style>
.app{
width: 300px;
height: 300px;
background-color: aquamarine;
}
</style>
修改子组件中{{msg}}-->{{msg.msg}}
再次点击按钮查看效果: