vxe-table 实现数据滚动轮播

在数据可视化大屏、监控中心或信息展示类后台中,表格数据自动轮播(跑马灯效果)是常见需求——无需用户操作,数据行按固定速度持续向上滚动,营造动态、实时的视觉氛围。
vxe-table 本身不内置轮播功能,但借助其滚动控制 API 和虚拟滚动能力,我们可以轻松实现一个平滑、可控、高性能的自动轮播表格。
本文将逐步拆解实现方案,并讲解滚动条隐藏、速度调节、触底停止等关键细节。

需求分析与实现思路

目标:表格数据加载后,自动以设定速度向上滚动,滚动到底部后停止(或循环),并支持用户手动控制开始/停止、调整滚动速度、切换滚动条显示状态。

  • 核心思路:
    • 通过 vxe-table 的 scrollTo({ top }) 方法精确控制滚动位置
    • 使用 setInterval(或 setTimeout 递归)每隔固定时间(如 100ms)将滚动位置增加指定像素值
    • 每次滚动后,通过 getScrollData() 获取当前滚动状态,判断是否已触底(isBottom)
    • 开启虚拟滚动(virtualYConfig)以支持大数据量(本例加载 5000 行)流畅滚动
    • 通过 scrollbarConfig.y.visible 控制滚动条显隐,营造“无干扰”轮播效果

核心配置与 API 详解

表格基础配置

const gridOptions = reactive({
  border: true,
  height: 400,                // 固定容器高度,滚动基于此区域
  virtualYConfig: {           // 开启纵向虚拟滚动,支持海量数据
    enabled: true,
    gt: 0                     // 数据量大于 0 即启用
  },
  scrollbarConfig: {          // 滚动条配置
    y: { visible: 'hidden' }  // 隐藏纵向滚动条(但滚动仍有效)
  },
  columns: [ /* ... */ ],
  data: []                    // 初始空,异步加载
})
  • 关键点:
    • height 必须固定,滚动轮播依赖可视区域高度
    • virtualYConfig.enabled = true 确保 5000 行数据渲染流畅,否则 DOM 节点过多会卡顿
    • scrollbarConfig.y.visible = 'hidden' 隐藏滚动条,视觉上更像“轮播”;若需保留滚动条可设为 'auto'(用户仍可手动拖拽,与自动滚动共存)

滚动控制 API

方法 说明
scrollTo({ top }) 将表格纵向滚动到指定像素位置(top 为距离顶部的像素值)
getScrollData() 返回当前滚动状态:

利用这两个 API,我们可以实现步进式滚动:

const { scrollTop, isBottom } = $grid.getScrollData()
if (!isBottom) {
  $grid.scrollTo({ top: scrollTop + step })  // step 为每次滚动的像素值
}

速度控制(步进值)

过单选按钮绑定 speedNum(取值 1、3、6、12),作为每次滚动的像素增量。
结合定时器间隔(固定 100ms),速度与 speedNum 成正比:

代码

table_other_auto_scroll

<template>
  <div>
    <vxe-button status="primary" @click="startRollEvent">开始</vxe-button>
    <vxe-button status="error" @click="stopRollEvent">停止</vxe-button>
    <br />
    <vxe-radio-group v-model="scrollbarConfig.y.visible">
      <vxe-radio-button checked-value="auto" content="显示滚动条"></vxe-radio-button>
      <vxe-radio-button checked-value="hidden" content="不显示滚动条"></vxe-radio-button>
    </vxe-radio-group>
    <br />
    <vxe-radio-group v-model="speedNum">
      <vxe-radio-button :checked-value="1" content="慢"></vxe-radio-button>
      <vxe-radio-button :checked-value="3" content="中"></vxe-radio-button>
      <vxe-radio-button :checked-value="6" content="快"></vxe-radio-button>
      <vxe-radio-button :checked-value="12" content="极速"></vxe-radio-button>
    </vxe-radio-group>

    <vxe-grid ref="gridRef" v-bind="gridOptions" v-on="gridEvents"></vxe-grid>
  </div>
</template>

<script setup>
import { ref, reactive, onUnmounted } from 'vue'

const gridRef = ref()
const speedNum = ref(3)

const scrollbarConfig = reactive({
  y: {
    visible: 'hidden'
  }
})
const gridOptions = reactive({
  border: true,
  height: 400,
  loading: false,
  virtualYConfig: {
    enabled: true,
    gt: 0
  },
  scrollbarConfig,
  columns: [
    { type: 'seq', width: 70 },
    { field: 'name', title: 'Name' },
    { field: 'nickname', title: 'Nickname' },
    { field: 'sex', title: 'Sex' },
    { field: 'age', title: 'Age' },
    { field: 'address', title: 'Address' }
  ],
  data: []
})

const gridEvents = {
  dataChange() {
    // 数据加载后启动
    startRollEvent()
  }
}
const loadList = () => {
  gridOptions.loading = true
  setTimeout(() => {
    const list = []
    for (let i = 0; i < 5000; i++) {
      list.push({
        id: 100000 + i,
        name: 'Test' + i,
        nickname: 'T' + i,
        role: 'Develop',
        sex: 'Man',
        age: 28,
        address: 'Shenzhen' + i
      })
    }
    gridOptions.loading = false
    gridOptions.data = list
  }, 250)
}

let autoTime = null
const handleScrollTo = () => {
  autoTime = setTimeout(() => {
    const $grid = gridRef.value
    if ($grid) {
      const { scrollTop, isBottom } = $grid.getScrollData()
      $grid.scrollTo({
        top: scrollTop + speedNum.value
      })
      // 如果触底则结束滚动
      if (!isBottom) {
        handleScrollTo()
      }
    }
  }, 100)
}

const startRollEvent = () => {
  stopRollEvent()
  handleScrollTo()
}

const stopRollEvent = () => {
  // 销毁滚动
  if (autoTime) {
    clearTimeout(autoTime)
  }
}

onUnmounted(() => {
  stopRollEvent()
})

loadList()
</script>

关键细节与注意事项

触底停止 vs 循环滚动

上述代码中,滚动到底部后自动停止。若需无限循环(即到底后跳回顶部重新开始),可在 isBottom 为 true 时执行:

if (isBottom) {
  $grid.scrollTo({ top: 0 })   // 瞬间跳回顶部
  // 继续滚动(需在跳转后再启动下一次)
  setTimeout(() => stepScroll(), 0)
} else {
  // 正常步进
}

但需注意:scrollTo 跳转是瞬间完成的,视觉上可能突兀,可结合 scrollTop 重置的平滑动画(vxe-table 暂不支持动画,可考虑 requestAnimationFrame 插值)。

滚动条显隐与用户交互

  • 隐藏滚动条(visible: 'hidden')后,用户仍可通过鼠标滚轮或触摸板滚动,但看不到滚动条滑块,适合大屏展示。
  • 显示滚动条(visible: 'auto')时,自动滚动与手动拖拽会共存,但用户拖拽会干扰自动滚动(因为滚动位置被改变)。如需禁用用户手动滚动,可设置 scrollbarConfig.y.visible = 'hidden' 并同时设置 CSS pointer-events: none 阻止鼠标滚轮(但可能影响交互,需按场景取舍)。

性能优化

  • 虚拟滚动必须开启(virtualYConfig.enabled: true),否则 5000 行全量渲染会导致严重的性能问题。
  • 定时器间隔建议不低于 50ms,避免过度频繁的 DOM 操作导致掉帧。
  • 数据量极大(如数万行)时,虚拟滚动仍能保持流畅,但 scrollTo 的计算量会随滚动位置增加而略微上升,通常可接受。

清除定时器

务必在组件销毁前清除定时器,否则可能导致内存泄漏或滚动继续。已在 onUnmounted 中处理。

通过 vxe-table 的 scrollTo 和 getScrollData API,我们仅用少量代码就实现了数据表格的自动轮播。结合虚拟滚动和滚动条控制,既能支撑大数据量,又能提供干净、专注的视觉体验。
该方案可直接用于大屏数据展示、实时监控列表等场景,且扩展性强(循环、暂停、速度调节等均可按需定制

https://vxetable.cn

posted @ 2026-08-24 13:29  你个老六  阅读(2)  评论(0)    收藏  举报