Skip to content

虚拟滚动

当数据选项数量较多时(如上千条),二级面板内置虚拟滚动机制,只渲染视口内可见的选项节点,保证滚动流畅不卡顿。

虚拟滚动对 radio(单选)、checkbox(多选)、map(标签)三种类型的二级面板均生效,无需额外配置。配合 panel-max-height 可控制下拉面板的滚动区域高度。

<template>
  <ClientOnly>
    <tiny-search-box
      v-model="tags"
      :items="items"
      panel-max-height="300px"
    />
  </ClientOnly>
</template>

<script setup lang="ts">
import { ref } from "vue";
import { virtualScrollDataSource } from "./virtual-scroll-data";

const items = virtualScrollDataSource;
const tags = ref([]);
</script>

工作原理

  • 固定行高(32px),通过滚动监听计算当前可视区域
  • 只渲染视口内 + 上下各 5 行缓冲项,DOM 节点数恒定(约 20~30 个)
  • 使用占位元素撑开总高度,内容容器通过 translateY 定位到正确位置
  • 搜索输入变化时自动重置滚动位置到顶部

Data Source

ts
// 生成大数据量数据源,用于演示二级面板数据选项的虚拟滚动效果

// 生成 1000 个单选选项
function generateRadioOptions(count: number) {
  return Array.from({ length: count }, (_, i) => ({
    label: `选项-${String(i + 1).padStart(4, '0')}`,
    id: `radio-${i + 1}`
  }))
}

// 生成 500 个多选选项
function generateCheckboxOptions(count: number) {
  return Array.from({ length: count }, (_, i) => ({
    label: `区域-${String(i + 1).padStart(4, '0')}`,
    id: `region-${i + 1}`
  }))
}

// 生成 200 个标签(map)选项,每个含 20 个子值
function generateMapOptions(groupCount: number, childCount: number) {
  return Array.from({ length: groupCount }, (_, i) => ({
    label: `标签组-${String(i + 1).padStart(3, '0')}`,
    id: `tag-group-${i + 1}`,
    options: Array.from({ length: childCount }, (_, j) => ({
      label: `值-${i + 1}-${j + 1}`,
      id: `tag-value-${i + 1}-${j + 1}`
    }))
  }))
}

export const virtualScrollDataSource = [
  {
    label: '单选项(1000条)',
    field: 'radioLarge',
    replace: true,
    options: generateRadioOptions(1000)
  },
  {
    label: '多选项(500条)',
    field: 'checkboxLarge',
    type: 'checkbox',
    options: generateCheckboxOptions(500)
  },
  {
    label: '标签(200组x20值)',
    field: 'mapLarge',
    type: 'map',
    searchKeys: ['label', 'id'],
    options: generateMapOptions(200, 20)
  }
]