Vue3搭配v-if使用ref获取DOM/组件实例返回true或null如何解决
Vue3 v-if控制的组件ref获取异常问题解决方案
问题根因
- 绑定ref的
<scroll>组件被v-if="songs.length"控制渲染:当songs为空时组件不会挂载,scrollRef.value自然为null;只有当songs长度大于0且组件完成挂载后,ref才会被赋值为组件实例。 - Vue的响应式更新是异步批量执行的:当songs从空变为有值时,DOM不会立刻渲染完成,此时如果立即读取
scrollRef.value,会因为组件还没挂载完成拿到null。 - 代码存在冗余的重复
v-if判断:template标签、scroll组件、song-list组件都用了同一个songs.length判断,额外增加了组件挂载/销毁的时序波动,可能导致ref赋值延迟。
修复方案
- 先删除冗余的v-if判断,只保留一层即可,减少不必要的组件销毁重建:
<template> <div class="music-list"> <scroll :options="scrollOptions" v-if="songs.length" @scroll="onScroll" ref="scrollRef" > <song-list :songs="songs" :playlist="playlist" class="song-list-ref" @scroll="onScroll" > </song-list> </scroll> </div> </template>
- 如果需要在songs更新后立即操作scroll实例,配合
nextTick等待DOM更新完成再读取ref:
import { watch, nextTick } from 'vue' const { songs, playlist, creator, resolvedIcons } = useRouterHook(Icons) const scrollRef = ref<any>(null) // 监听songs长度变化,组件挂载完成后再操作ref watch(() => songs.length, async (newVal) => { if (newVal > 0) { await nextTick() // 此处scrollRef.value已经是正确的组件实例 console.log(scrollRef.value) } }) function onScroll(pos: any): void { const y: number = -pos.y // 访问ref前增加非空判断,避免组件销毁过程中触发事件报错 if (!scrollRef.value) return console.log(scrollRef.value) }
- 如果scroll组件不需要在songs为空时销毁,可以把
v-if换成v-show,组件会一直保留在DOM中,ref不会变成null:
<scroll :options="scrollOptions" v-show="songs.length" @scroll="onScroll" ref="scrollRef" >
注意:如果scroll组件初始化依赖内部DOM的宽高计算,
v-show在初始隐藏状态下初始化可能出现计算异常,这种场景更推荐用v-if + nextTick的方案。
关于ref.value返回true的异常
正常情况下绑定组件的ref.value只会是null或者组件实例对象,不会返回布尔值,请检查代码中是否有其他地方手动给scrollRef.value赋值为true的逻辑。
内容的提问来源于stack exchange,提问作者snowingfox
相关产品推荐
相关产品推荐

