非父子组件通信(父传孙)
父组件传递给孙组件:通过provide/inject来共享数据。
在一些深度嵌套的场景中,子组件要想获取父组件里面的部分数据,可以使用props逐级传递的方法,但这样会显得非常麻烦。所以在这种场景下,一般父组件使用provide来提供数据,而子孙组件使用inject来使用父组件提供的数据。
一般使用
三个组件,app.vue home.vue homecontent.vue,这三个为层层嵌套关系。
""" app.vue """
<template>
<home/>
</template>
<script>
import Home from "./home";
export default {
name: "App",
components: {Home},
}
</script>
""" home.vue """
<template>
<homecontent/>
</template>
<script>
import Homecontent from "./homecontent";
export default {
name: "home",
components: {Homecontent}
}
</script>
""" homecontent.vue """
<template>
<div>
孙组件
</div>
</template>
<script>
export default {
name: "homecontent"
}
</script>
在父组件中使用provide来定义数据。
""" app.vue 父组件 """
<template>
<home/>
</template>
<script>
import Home from "./home";
export default {
name: "App",
components: {Home},
provide: {
name: "xxcfun",
age: "18"
}
}
</script>
在孙组件中使用inject来使用这些数据。
""" homecontent.vue 孙组件 """
<template>
<div>
孙组件 <br/>
{{name}} - {{age}}
</div>
</template>
<script>
export default {
name: "homecontent",
inject: ["name", "age"]
}
</script>
这样就能实现非父子组件之间共享数据:
zjtxfs.png
拓展用法
- 使用data定义的数据
如果在父组件中想使用data里面定义的数据,直接在provide中使用this来指向data数据是行不通的,在provide作用域里面是拿不到data数据的,会出现undefined的情况。
如果有这样的需求,得在provide中做下修改,把对象数据改为函数返回对象的格式。
""" app.vue """
<template>
<home/>
</template>
<script>
import Home from "./home";
export default {
name: "App",
components: {Home},
provide() {
return {
name: "xxcfun",
age: "18",
hobby: this.hobby,
hobbynum: this.hobby.length
}
},
data() {
return {
hobby: ["football", "bike"]
}
}
}
</script>
""" homecontent.vue """
<template>
<div>
孙组件 <br/>
{{name}} - {{age}} <br/>
{{hobby}} - {{hobbynum}}
</div>
</template>
<script>
export default {
name: "homecontent",
inject: ["name", "age", "hobby", "hobbynum"]
}
</script>
zjtxdata.png
- 使用响应式数据
在父组件中添加一个点击事件,增加一个hobby。
""" app.vue """
<template>
<home/>
<button @click="addHobby">添加一个hobby</button>
</template>
<script>
import Home from "./home";
export default {
name: "App",
components: {Home},
provide() {
return {
name: "xxcfun",
age: "18",
hobby: this.hobby,
hobbynum: this.hobby.length
}
},
data() {
return {
hobby: ["football", "bike"]
}
},
methods: {
addHobby() {
this.hobby.push("games")
}
}
}
</script>
在点击一次按钮后,会发现孙组件hobby的内容添加上了games,但后面的长度还是显示2。
zjtxerro.png
有这样的需求的话,这里得需要用到一个计算属性,每次hobby改变的时候,length也实时进行计算。
""" app.vue """
<template>
<home/>
<button @click="addHobby">添加一个hobby</button>
</template>
<script>
import Home from "./home";
import { computed } from "vue";
export default {
name: "App",
components: {Home},
provide() {
return {
name: "xxcfun",
age: "18",
hobby: this.hobby,
hobbynum: computed(() => this.hobby.length)
}
},
data() {
return {
hobby: ["football", "bike"]
}
},
methods: {
addHobby() {
this.hobby.push("games")
}
}
}
</script>
这样点击两次后,增加了两个games,后面的数量也变成了4。
zjtxcom.png
~END