vue3 虛擬滾動勾子

122 阅读1分钟

虛擬滾動勾子


import { ref, reactive, watch,isRef,nextTick  } from "vue";
export const useVirtualList = (dataLen, config) => {
  let { start = 0, end, itemHeight, className, tableHeight } = config || {};

  const virtualList = reactive({
    start,
    end,
    itemHeight,
    tableHeight,
    className,
    currentOffset: 0,
    wrapperDom: null,
    contentDom: null,
  });
  // 计算 end count className
  const isDynamicHeight = isRef(tableHeight); //是否传入的表格高度是动态的
  virtualList.end = end || parseInt((isDynamicHeight ? tableHeight.value : tableHeight) / itemHeight);
  virtualList.count = virtualList.end - start;
  className = `${virtualList.className ? "." + virtualList.className + " " : ""}`;

  const init = () => {
    // 获取container和content元素
    virtualList.wrapperDom = document.querySelector(`${className}.ant-table-body`);
    virtualList.contentDom = document.querySelector(`${className}.ant-table-body table`);
    if (!virtualList.wrapperDom || !virtualList.contentDom) return;

    // 样式调整
    virtualList.wrapperDom.style.position = "relative";
    virtualList.wrapperDom.style.top = virtualList.wrapperDom.style.left = "0";
    virtualList.contentDom.style.position = "absolute";
    virtualList.wrapperDom.addEventListener("scroll", handleScroll);

    // 创建占位元素,撑起高度
    let isExist = document.querySelector(`${className}.palceholder-dom`);
    if (isExist) virtualList.wrapperDom?.removeChild(isExist);
    const placeHolderDom = document.createElement("div");
    placeHolderDom.className = "palceholder-dom";
    virtualList.wrapperDom.appendChild(placeHolderDom);
    placeHolderDom.style.height = dataLen * virtualList.itemHeight + "px";
  };

  const handleScroll = () => {
    // 获取偏移量
    const scrollTop = virtualList.wrapperDom.scrollTop;
    // 重新计算start end
    virtualList.start = Math.ceil(scrollTop / virtualList.itemHeight);
    virtualList.end = virtualList.start + virtualList.count;
    // contentDom元素进行偏移,保证视觉可见
    virtualList.currentOffset = scrollTop - (scrollTop % virtualList.itemHeight);
    virtualList.contentDom.style.transform = `translateY(${virtualList.currentOffset}px)`;
  };

  nextTick(() => {
    init();
  });
  return virtualList;
};

頁面使用

import { useVirtualList  } from "@/use/useVirtualList";

watch(tableData, () => {
  virtualList.value = useVirtualList(tableData.value.length, {
    end:14,
    className: 's-table',
    itemHeight: 71,
  });
})
const showData = computed(() => tableData.value.slice(virtualList.value.start, virtualList.value.end))

<s-table class="s-table"   :columns="columns" :data-source="showData" :pagination="false" :scrollX="2500">