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

Vue3组合式API中如何获取元素offsetTop并实现滚动?

解决Vue3组合式API中动态ref获取元素offsetTop失效的问题

问题核心

你通过v-for给Disclosure组件绑定动态ref时,存入数组的是组件实例,不是DOM元素。直接读取代理后的组件实例的offsetTop自然会失败——这个属性属于DOM元素,而非Vue组件实例。

两种解决方案

方案1:修改Disclosure组件(若有权限)

如果能编辑Disclosure组件的源码,直接在组件内部暴露根DOM元素:

<!-- Disclosure.vue -->
<script setup>
import { ref, defineExpose } from 'vue'
const rootEl = ref(null)
// 暴露根元素给父组件
defineExpose({ rootEl })
</script>

<template>
  <div ref="rootEl"> <!-- 给组件根元素绑定ref -->
    <!-- 组件内部内容 -->
  </div>
</template>

父组件中直接访问暴露的根元素:

<script setup>
import { ref, nextTick } from 'vue'
import Disclosure from './Disclosure.vue'

const accordions = ref([])

const scrollToTarget = async (index) => {
  await nextTick() // 确保DOM已完成渲染
  const targetComp = accordions.value[index]
  if (!targetComp?.rootEl) return
  
  const offsetTop = targetComp.rootEl.offsetTop
  window.scrollTo({
    top: offsetTop,
    behavior: 'smooth'
  })
}
</script>

<template>
  <Disclosure 
    v-for="(item, idx) in list" 
    :key="idx"
    :ref="el => el && (accordions.value[idx] = el)"
  />
  <button @click="scrollToTarget(1)">滚动到第二个面板</button>
</template>

方案2:直接获取组件的根DOM元素(无需修改组件)

如果无法修改Disclosure组件,Vue组件实例自带的$el属性会指向组件的根DOM元素,直接使用即可:

<script setup>
import { ref, nextTick } from 'vue'
import Disclosure from './Disclosure.vue'

const accordions = ref([])

const scrollToTarget = async (index) => {
  await nextTick()
  const targetComp = accordions.value[index]
  if (!targetComp) return
  
  const domEl = targetComp.$el
  const offsetTop = domEl.offsetTop
  window.scrollTo({
    top: offsetTop,
    behavior: 'smooth'
  })
}
</script>

<template>
  <Disclosure 
    v-for="(item, idx) in list" 
    :key="idx"
    :ref="el => el && (accordions.value[idx] = el)"
  />
  <button @click="scrollToTarget(0)">滚动到第一个面板</button>
</template>

关键注意事项

  • 动态ref的回调要判断el是否存在:组件卸载时el会变为null,避免把null存入数组导致后续报错。
  • 必须用nextTick:Vue的DOM更新是异步的,尤其是初始化或数据更新后立即调用滚动时,要等DOM渲染完成才能正确获取offsetTop。
  • 第三方组件特殊情况:如果Disclosure是第三方UI组件,部分组件可能会把根元素包裹在多个容器里,此时可以通过$el.querySelector定位到目标元素,或者查看组件文档是否有官方提供的ref获取方式。

内容的提问来源于stack exchange,提问作者Sascha

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 04:15:39