Vue3 + element-plus el-table二次封装组件新增虚拟滚动功能

1、此功能已集成到TTable组件TSelectTable

2、最终效果(基于element-plus 的 el-table组件)

3、TTable或TSelectTable组件使用(只需要在标签中设置useVirtual即可)

4、源码(可以提取当做hooks方式来使用--具体看组件源码)

js 复制代码
// 初始化数据
let state = reactive({
  tableData: props.table.data
})
// 渲染实际高度的容器
const actualHeightContainerEl = ref<HTMLElement | any>(null)
// 用于偏移的元素选择器
const translateContainerEl = ref<HTMLElement | any>(null)
// 滚动容器的元素选择器
const scrollContainerEl = ref<HTMLElement | any>(null)
// 所有数据
const saveDATA: Ref<any[]> = ref([])
// 缓存已渲染元素的高度
const RenderedItemsCache: any = {}
watch(
  () => props.table.data,
  val => {
    // console.log(111, val)
    if (props.useVirtual) {
      saveDATA.value = val
      updateRenderData(0)
    } else {
      state.tableData = val
    }
  },
  { deep: true }
)
onMounted(() => {
  if (props.useVirtual) {
    saveDATA.value = props.table.data
    actualHeightContainerEl.value = document.querySelector(
      ".t_table_use_virtual .el-scrollbar__view"
    )
    translateContainerEl.value = document.querySelector(".t_table_use_virtual .el-table__body")
    scrollContainerEl.value = document.querySelector(".t_table_use_virtual .el-scrollbar__wrap")
    scrollContainerEl.value?.addEventListener("scroll", handleScroll)
  }
})
// 更新实际渲染数据
const updateRenderData = (scrollTop: number) => {
  let startIndex = 0
  let offsetHeight = 0
  for (let i = 0; i < saveDATA.value.length; i++) {
    offsetHeight += getItemHeightFromCache(i)
    if (offsetHeight >= scrollTop) {
      startIndex = i
      break
    }
  }
  // 计算得出的渲染数据(props.virtualShowSize初始化显示条数)
  state.tableData = saveDATA.value.slice(startIndex, startIndex + props.virtualShowSize)
  // 缓存最新的列表项高度
  updateRenderedItemCache(startIndex)
  // 更新偏移值
  updateOffset(offsetHeight - getItemHeightFromCache(startIndex))
}
// 滚动事件
const handleScroll = (e: any) => {
  // 渲染正确的数据
  updateRenderData(e.target.scrollTop)
  // console.log("滚动事件---handleScroll")
}
// 移除滚动事件
onBeforeUnmount(() => {
  // console.log("移除滚动事件")
  if (props.useVirtual) {
    scrollContainerEl.value?.removeEventListener("scroll", handleScroll)
  }
})
// 获取缓存高度,无缓存,取配置项的 itemHeight(设置每行高度50px)
const getItemHeightFromCache = (index: number | string) => {
  const val = RenderedItemsCache[index]
  return val === void 0 ? 50 : val
}
// 更新实际高度
const updateActualHeight = () => {
  let actualHeight = 0
  saveDATA.value.forEach((_, i) => {
    actualHeight += getItemHeightFromCache(i)
  })
  actualHeightContainerEl.value!.style.height = actualHeight + "px"
}
// 更新偏移值
const updateOffset = (offset: number) => {
  if (translateContainerEl.value && translateContainerEl.value.style) {
    translateContainerEl.value!.style.transform = `translateY(${offset}px)`
  }
}
// 更新已渲染列表项的缓存高度
const updateRenderedItemCache = (index: number) => {
  // 当所有元素的实际高度更新完毕,就不需要重新计算高度
  const shouldUpdate = Object.keys(RenderedItemsCache).length < saveDATA.value.length
  if (!shouldUpdate) return
  nextTick(() => {
    // 获取所有列表项元素
    const Items: HTMLElement[] = Array.from(
      document.querySelectorAll(".t_table_use_virtual .el-table__row")
    )
    // 进行缓存
    Items.forEach(el => {
      if (!RenderedItemsCache[index]) {
        RenderedItemsCache[index] = el.offsetHeight
      }
      index++
    })
    // 更新实际高度
    updateActualHeight()
  })
}

组件地址

gitHub组件地址

gitee码云组件地址

相关文章

基于ElementUi再次封装基础组件文档

vue3+ts基于Element-plus再次封装基础组件文档

相关推荐
宿67410 小时前
vue3-async
前端·javascript·vue.js
Dreams°12317 小时前
【Java后端+Vue前后端分离:内网正常、公网访问异常|5个高频经典踩坑完整复盘】
java·开发语言·vue.js
小蒜学长17 小时前
基于Springboot+Vue的环保行动志愿者招募系统设计与实现(代码+数据库+LW)
java·数据库·vue.js·spring boot·后端
天道kabuto18 小时前
踩坑复盘:为什么在输入框按个回车,页面就偷偷刷新了?
vue.js
吴长建先生18 小时前
Vue.js支付回调页面如何设计才能保障对账准确性?
vue.js
leoZ23118 小时前
第 2 篇:搭建地基——Vue3 + Vite + Tailwind v4 + shadcn-vue
前端·javascript·vue.js·人工智能·目标检测·数据挖掘·语音识别
吴长建先生19 小时前
支付回调接口设计与代码规范:如何提升团队工程化能力
vue.js
zttbee19 小时前
vue2的API大白话讲解
前端·vue.js·前端框架
卤蛋fg61 天前
vue 抽屉组件挂载到指定元素内显示,,表格自适应弹窗宽高
vue.js
我就是DaLing呀!1 天前
vue3 + 独立的数据管理 Store实现视频剪辑功能
前端·typescript·vue3·canvas·store