这节课我们来学习在组合式api里面使用依赖注入(provide、inject)和ref获取dom元素。
我们在组件之间传递数据时一般都是使用props
。但这种方式在多级组件之间传递数据是非常繁琐的,我们需要逐级传递,才能把数据传递给最终的组件。例如下图所示:
在我们使用依赖注入之后,可以很方便了帮助我们向嵌套更深的子孙级组件传递数据,例如下图所示:
在选项式api里面我们其实已经对provide、inject
有过学习,所以我们这里就不过多讲解了,我们直接来看在组合式api里面怎么使用provide、inject
传递数据。
假设我们有三个组件 App.vue → Footer.vue → DeepChild.vue。然后我们希望在App
组件里面能直接传递数据给子孙组件DeepChild
。我们先到app组件里面来提供数据。
<script>
import { ref,provide} from 'vue'
......
export default{
......
setup(){
provide("message","Hello World!")
}
}
</script>
完了之后我们再到DeepChild组件里面来获取
<script>
import {inject} from "vue"
......
export default{
......
setup(){
const message = inject("message")
return{
message
}
}
}
</script>
和响应式数据配合使用
通过响应式数据配合使用实现可修改的依赖注入数据。
提供数据,顺带把数据的修改方式也一并提供过去
<script>
import { ref,provide,readonly} from 'vue'
......
export default{
......
setup(){
const message = ref("hello world!")
provide("message",message)
provide("changeMessage",(msg)=>{
message.value=msg
})
}
}
</script>
获取数据
<script>
import {inject} from "vue"
export default{
setup(){
const message = inject("message")
const changeMessage = inject("changeMessage")
const changeMsg = ()=>{
changeMessage("hello vue")
}
return{
message,
changeMsg
}
}
}
</script>
这样就实现了数据的修改,但是我们会发现一个问题,我给message传递的是一个ref响应式数据,那我们为何不直接在子组件里面来修改这个响应式数据。比如:
const changeMsg = ()=>{
message.value="hello vue"
}
其实这样它也是能达到修改目的的,只不过我们不建议这样编写代码,因为我们应该遵守vue的单项数据流原则,使用由数据提供者来修改提供数据。避免编写这样的屎山代码。
为了避免以上代码的出现,我可以使用readonly
包装起来让提供的响应式数据变得不修可改。
setup(){
const message = ref("hello world!")
provide("message",readonly(message))
provide("changeMessage",(msg)=>{
message.value=msg
})
}
代码优化
//App.vue组件
//用一个对象来打包提供的数据,这样代码看起清晰简洁
setup(){
const message = ref("hello world!")
provide("message",{
message:readonly(message),
setMessage(msg){
message.value=msg
}
})
}
//DeepChild.vue组件
// 使用对象解构的方式来获取数据和修改方法
setup(){
const {message,setMessage} = inject("message")
const changeMsg = ()=>{
setMessage("hello vue")
}
return{
message,
changeMsg
}
}
我们在选项式api里面可以通过给模版设置一个ref属性,然后通过this.$refs.xxx获取到指定版本的dom,如果是组件可以获取组件的实例。
那么我们在组合式api里面怎么实现呢。我们在footer.vue组件里面来给大家讲解一下
<script>
import DeepChild from "./DeepChild.vue"
import {ref,onMounted} from "vue"
export default{
components:{
DeepChild
},
setup(){
//通过ref来实名一个null的响应式对象
const footer = ref(null)
onMounted(()=>{
//打印一下deom结果里的innerText属性
console.log(footer.value.innerText)
})
return{
//这里同样是需要进行返回的
footer
}
}
}
</script>
<template>
<!--然后将我们声明的空响应式对象名称放指定元素ref属性里-->
<div ref="footer">
Footer
<DeepChild/>
</div>
</template>