You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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赋值延迟。

修复方案

  1. 先删除冗余的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>
  1. 如果需要在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)
}
  1. 如果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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 22:36:04