最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于Vue3+Element-Plus實(shí)現(xiàn)自定義虛擬表格滾動(dòng)的方案

 更新時(shí)間:2026年02月10日 08:37:14   作者:程序員大衛(wèi)  
本文介紹了如何基于Vue3和ElementPlus實(shí)現(xiàn)一個(gè)自定義的虛擬滾動(dòng)表格方案,該方案支持不等高行、緩存高度、緩沖區(qū)渲染,并且與el-table解耦,通過使用VirtualListTable組件,可以在不修改el-table代碼的前提下,為表格提供高性能的虛擬滾動(dòng)能力,需要的朋友可以參考下

背景

本文將基于 Vue3 + Element Plus,實(shí)現(xiàn)一個(gè)完全自定義的虛擬滾動(dòng)表格方案,支持不等高行、緩存高度、緩沖區(qū)渲染,并且與 el-table 解耦。

Element Plus 雖然提供了虛擬滾動(dòng),但目前還是測(cè)試(beta)階段,所以暫時(shí)先沒用了,其實(shí)當(dāng)時(shí)寫這個(gè)組件主要是為了給 Element UI 使用的。

一、如何使用

在實(shí)際業(yè)務(wù)中,如果你正在使用 Element Plus 的 el-table,又遇到了大數(shù)據(jù)量導(dǎo)致滾動(dòng)卡頓的問題,那么這個(gè)組件可以在不改 el-table 任何代碼的前提下,為表格提供一套高性能的虛擬滾動(dòng)能力。

使用方式非常簡(jiǎn)單:只需要用 VirtualListTable 包一層 el-table,并通過 change 事件接收當(dāng)前需要渲染的數(shù)據(jù)即可。

  • VirtualListTable 負(fù)責(zé)滾動(dòng)、計(jì)算可視區(qū)和緩沖區(qū)數(shù)據(jù),
  • el-table 只負(fù)責(zé)展示當(dāng)前這一小段數(shù)據(jù),二者完全解耦。
<script>
// 渲染虛擬數(shù)據(jù)
const renderVirtualData = (data)=>{
    tableData.value = data;
}
</script>

<VertualListTable :list-data="largeData" @change="renderVirtualData">
    <el-table :data="tableData">
        <el-table-column prop="name" label="Name" />
        <el-table-column prop="address" label="Address" />
    </el-table>
</VertualListTable>

二、VirtualListTable 核心實(shí)現(xiàn)解析

1?? 虛擬滾動(dòng)的關(guān)鍵變量

const start = ref(0);                 // 當(dāng)前起始索引
const cacheHeight = new Map();        // 行高緩存
let positions: Positions = [];        // 每一行的位置 & 高度
let scrollTop = 0;

positions 的結(jié)構(gòu):

{
  id: number | string,
  height: number,
  top: number
}

這是整個(gè)虛擬滾動(dòng)的“地圖”。

2?? 可視區(qū)數(shù)據(jù)計(jì)算(含 buffer)

const visibleCount = computed(() =>
  Math.ceil(props.height / props.estimatedItemSize)
);

const visibleData = computed(() => {
  const startIndex = Math.max(start.value - props.bufferCount, 0);
  const endIndex = Math.min(
    start.value + visibleCount.value + props.bufferCount,
    props.listData.length,
  );
  return props.listData.slice(startIndex, endIndex);
});

為什么要 buffer?

  • 防止?jié)L動(dòng)時(shí)白屏
  • 提前渲染上下緩沖區(qū)域,提升體驗(yàn)

3?? 滾動(dòng)時(shí)如何快速定位起始索引(關(guān)鍵)

這里使用的是 二分查找。

const getStartIndex = (list: Positions, scrollTop: number) => {
  let index = null;
  let low = 0;
  let high = list.length - 1;

  while (low <= high) {
    const mid = low + ((high - low) >> 1);
    const midVal = list[mid]?.top;
    if (midVal <= scrollTop) {
      index = mid;
      low = mid + 1;
    } else {
      high = mid - 1;
    }
  }
  return index ?? 0;
};

時(shí)間復(fù)雜度從 O(n) 降到 O(log n),在大數(shù)據(jù)量下非常關(guān)鍵。

4?? 使用 transform 控制真實(shí) DOM 偏移

const setStartOffset = () => {
  const index = Math.max(start.value - props.bufferCount, 0);
  const offset = positions[index]?.top ?? 0;
  contentRef.value!.style.transform =
    `translate3d(0, ${offset}px, 0)`;
};
  • 不操作 top
  • 使用 transform,避免觸發(fā)重排
  • GPU 加速,滾動(dòng)更順滑

5?? 不等高行的核心:高度緩存 + ResizeObserver

const updateItemsSize = () => {
  getNodes().forEach((node) => {
    const id = getNodeId(node);
    const height = node.getBoundingClientRect().height;
    cacheHeight.set(id, height);
  });
};

結(jié)合 ResizeObserver

ro = new ResizeObserver(() => {
  if (ignoreResize) return;
  updateLayout();
});

解決的問題:

  • 表格行高度動(dòng)態(tài)變化
  • 文本換行、slot 變化
  • 不需要強(qiáng)制固定行高

6?? 占位元素?fù)伍_滾動(dòng)條

這是虛擬滾動(dòng)中最核心的一步:DOM 只渲染幾十行,但滾動(dòng)條看起來像有幾千行

<div ref="placeholder" class="placeholder"></div>
const updateTotalHeight = () => {
  const lastItem = positions.at(-1);
  placeholderRef.value!.style.height =
    (lastItem.top + lastItem.height) + 'px';
};

三、與 el-table 的無侵入融合

  • 不改 el-table 源碼
  • 只接管滾動(dòng)容器
  • 所有表格功能照常使用(排序、列、樣式)
const initElement = () => {
  const $wrapper = containerRef.value
    ?.querySelector('.el-table__body-wrapper');
  const $tableBody = $wrapper
    ?.querySelector('.el-scrollbar');

  contentRef.value?.appendChild($tableBody);
  $wrapper?.appendChild(scrollBoxRef.value!);
};

四、TableBigData:保持純展示

<el-table :data="data">
  <el-table-column prop="name" label="Name" />
  <el-table-column prop="email" label="Email" />
</el-table>

五、總結(jié)

1. 這個(gè)方案適合什么場(chǎng)景

  • 超大數(shù)據(jù)量表格(1000+)
  • 行高不固定
  • 老項(xiàng)目 + Element Plus
  • 對(duì)滾動(dòng)性能要求高

2. 方案優(yōu)勢(shì)

  • 支持不等高行
  • 與 el-table 解耦
  • 二分查找高性能
  • buffer 防白屏
  • ResizeObserver 自動(dòng)修正

以上就是基于Vue3+Element-Plus實(shí)現(xiàn)自定義虛擬表格滾動(dòng)的方案的詳細(xì)內(nèi)容,更多關(guān)于Vue3 Element-Plus虛擬表格滾動(dòng)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論

黑龙江省| 霍山县| 柳州市| 西贡区| 遂昌县| 石景山区| 古交市| 黄陵县| 桐城市| 正宁县| 光泽县| 沙田区| 鄂伦春自治旗| 偏关县| 错那县| 博客| 玉树县| 吴旗县| 工布江达县| 莆田市| 上思县| 江门市| 新泰市| 孟连| 灵武市| 吉林省| 北辰区| 东莞市| 黄平县| 遵义县| 五原县| 临夏县| 章丘市| 江川县| 周口市| 新泰市| 拉萨市| 广汉市| 延边| 万载县| 中江县|