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

Vue中如何在异步数据渲染DOM后获取目标元素并实现滚动?

解决Vue异步数据渲染后滚动到指定元素的问题

这问题我做列表滚动功能时也踩过同款坑!你遇到的核心问题是:Vue在created钩子中赋值异步数据后,并不会立刻更新DOM——DOM更新是异步任务,会被放到事件队列里延后执行,所以这时候调用document.getElementById('5'),自然找不到还没渲染出来的元素。

下面给你几种靠谱的解决方案,按Vue最佳实践排序:

方案1:使用$nextTick等待DOM更新完成

$nextTick是Vue专门提供的方法,用来在DOM更新完成后执行回调函数。把滚动逻辑放到$nextTick里,就能确保DOM已经渲染出所有列表项:

new Vue({
  el: '#app',
  async created () {
    const response = await axios.get("https://jsonplaceholder.typicode.com/todos")
    this.items = response.data
    // 等待DOM更新完成后再执行滚动
    this.$nextTick(() => {
      const selectedElement = document.getElementById('5')
      this.scrollTo(selectedElement)
    })
  },
  data: () => ({ items: [] }),
  methods: {
    scrollTo (selectedElement) {
      const scrollableDiv = document.getElementById('scrollableDiv')
      scrollableDiv.scrollTop = selectedElement.offsetTop
    }
  }
})

方案2:监听items数据变化(更适配动态场景)

如果你的items可能会被多次更新(比如分页加载、筛选操作),用watch监听items变化会更灵活,每次数据更新后自动触发滚动:

new Vue({
  el: '#app',
  async created () {
    const response = await axios.get("https://jsonplaceholder.typicode.com/todos")
    this.items = response.data
  },
  data: () => ({ items: [] }),
  watch: {
    items: {
      handler() {
        this.$nextTick(() => {
          const selectedElement = document.getElementById('5')
          if (selectedElement) { // 额外判断元素是否存在,避免报错
            this.scrollTo(selectedElement)
          }
        })
      },
      immediate: false // 初始空数组时不执行,只在数据变化时触发
    }
  },
  methods: {
    scrollTo (selectedElement) {
      const scrollableDiv = document.getElementById('scrollableDiv')
      scrollableDiv.scrollTop = selectedElement.offsetTop
    }
  }
})

方案3:使用Vue的ref(推荐的Vue风格)

尽量避免在Vue中直接用document.getElementById操作DOM,Vue提供的ref是更符合框架设计的方式,代码可读性和可维护性更好:

先修改HTML,给滚动容器和目标元素加ref:

<div id="app"> 
  <v-app> 
    <div id='scrollableDiv' ref="scrollableDiv"> 
      <p v-for='item in items' :id='item.id' :ref="item.id === 5 ? 'targetItem' : ''">
        {{item.title}}
      </p> 
    </div> 
  </v-app> 
</div>

然后在JS中通过this.$refs获取元素:

new Vue({
  el: '#app',
  async created () {
    const response = await axios.get("https://jsonplaceholder.typicode.com/todos")
    this.items = response.data
    this.$nextTick(() => {
      const selectedElement = this.$refs.targetItem[0] // v-for生成的ref是数组格式
      if (selectedElement) {
        this.scrollTo(selectedElement)
      }
    })
  },
  data: () => ({ items: [] }),
  methods: {
    scrollTo (selectedElement) {
      const scrollableDiv = this.$refs.scrollableDiv
      scrollableDiv.scrollTop = selectedElement.offsetTop
    }
  }
})

额外优化提示

如果滚动位置计算不准确(比如滚动容器有内边距、元素有外边距),可以用getBoundingClientRect()计算更精确的偏移量:

scrollableDiv.scrollTop = selectedElement.getBoundingClientRect().top - scrollableDiv.getBoundingClientRect().top + scrollableDiv.scrollTop

内容的提问来源于stack exchange,提问作者Eerik Sven Puudist

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:12:06