Vue2中通过$refs获取子组件里的computed值为undifined

221 阅读1分钟

背景:

我需要在父组件里调用子组件中的computed值,搜索发现可以通过$refs获取到子组件里的内容,于是乎,下面是伪代码:

<template>
    <children
        v-if="show"
    >{{ errorInfo }}</children>
</template>
<script>
export default {
    data() {
        return {
            show: true
        }
    }
    computed: {
        errorInfo() {
            if(this.$refs.children.errorInfo) {
                return this.$refs.children.errorInfo
            }
            return ""
        }
    }
}
</script>
<template>
</template>
<script>
export default {
    name: "children",
    computed:{
        errorInfo() {
            return "我是子组件的错误信息"
        }
    }
}
</script>

但很奇怪,我在父组件的show中打印this.$refs.children为undifined,更别说获取子组件里的内容了,而且我不管怎么在子组件里change值,父组件都无法改变是否展示,去网上搜索了下资料发现:

问题:

在vue2中,this.$refs的触发时机是在mounted之后,但如果我在父组件最开始就想展示, 上网查了一遍资料后发现:this.$refs的访问时机应该是在mounted之后。

官网有这么一句话:关于 ref 注册时间的重要说明:因为 ref 本身是作为渲染结果被创建的,在初始渲染的时候你不能访问它们 - 它们还不存在!$refs 也不是响应式的,因此你不应该试图用它在模板中做数据绑定。

所以,在这个场景下,this.$refs.children之所以为undifined,主要是因为在mounted之后,但是computed的触发主要是根据数据是否变更进行计算的,它是在mounted之前执行的,也就是一开始computed获取到的$refs为空,又由于$refs是非响应式的,也就是组件渲染与否,不会影响到computed的变化,所以show值并不会发生变化。

解决措施:

可以通过watch实现,watch监听show值是否为true并更新parentErrorInfo字段值,computed里的errorInfo则会根据parentErrorInfo字段值的更新来动态的获取this.$refs,伪代码如下:

<template>
    <children
        v-if="show"
    >{{ errorInfo }}</children>
</template>
<script>
export default {
    data() {
        return {
            show: true,
            parentErrorInfo: ""
        }
    },
    computed: {
        errorInfo() {
            if(this.parentErrorInfo) {
                return this.$refs.children.errorInfo
            }
            return ""
        }
    },
    watch:{
        show(newValue) {
            if(newValue){
                this.$nextTick(()=>{
                    this.parentErrorInfo = this.$refs.children.errorInfo
                })
            }
        }
    }
}
</script>