首页 > 其他分享 >Vue3 封装不定高虚拟列表 hooks

Vue3 封装不定高虚拟列表 hooks

时间:2024-10-10 11:00:11浏览次数:12  
标签:index const hooks number let dataSource Vue3 封装 config

// useVirtualList.ts

import { ref, onMounted, onBeforeUnmount, watch, nextTick } from "vue";
import type { Ref } from "vue";

interface Config {
  data: Ref<any[]>; // 数据源
  scrollContainer: string; // 滚动容器的元素选择器
  actualHeightContainer: string; // 用于撑开高度的元素选择器
  translateContainer: string; // 用于偏移的元素选择器
  itmeContainer: string;// 列表项选择器
  itemHeight: number; // 列表项高度
  size: number; // 每次渲染数据量
}

type HtmlElType = HTMLElement | null;

export default function useVirtualList(config: Config) {
  // 获取元素
  let actualHeightContainerEl: HtmlElType = null,
    translateContainerEl: HtmlElType = null,
    scrollContainerEl: HtmlElType = null;

  onMounted(() => {
    actualHeightContainerEl = document.querySelector(
      config.actualHeightContainer
    );
    scrollContainerEl = document.querySelector(config.scrollContainer);
    translateContainerEl = document.querySelector(config.translateContainer);
  });

  // 数据源,便于后续直接访问
  let dataSource: any[] = [];

  // 数据源发生变动
  watch(
    () => config.data.value,
    (newVla) => {
      // 更新数据源
      dataSource = newVla;

      // 计算需要渲染的数据
      updateRenderData(0);
    }
  );

  // 更新实际高度
  const updateActualHeight = () => {
    let actualHeight = 0;
    dataSource.forEach((_, i) => {
      actualHeight += getItemHeightFromCache(i);
    });

    actualHeightContainerEl!.style.height = actualHeight + "px";
  };

  // 缓存已渲染元素的高度
  const RenderedItemsCache: any = {};

  // 更新已渲染列表项的缓存高度
  const updateRenderedItemCache = (index: number) => {
    // 当所有元素的实际高度更新完毕,就不需要重新计算高度
    const shouldUpdate =
      Object.keys(RenderedItemsCache).length < dataSource.length;
    if (!shouldUpdate) return;

    nextTick(() => {
      // 获取所有列表项元素
      const Items: HTMLElement[] = Array.from(
        document.querySelectorAll(config.itmeContainer)
      );

      // 进行缓存
      Items.forEach((el) => {
        if (!RenderedItemsCache[index]) {
          RenderedItemsCache[index] = el.offsetHeight;
        }
        index++;
      });

      // 更新实际高度
      updateActualHeight();
    });
  };

  // 获取缓存高度,无缓存,取配置项的 itemHeight
  const getItemHeightFromCache = (index: number | string) => {
    const val = RenderedItemsCache[index];
    return val === void 0 ? config.itemHeight : val;
  };

  // 实际渲染的数据
  const actualRenderData: Ref<any[]> = ref([]);

  // 更新实际渲染数据
  const updateRenderData = (scrollTop: number) => {
    let startIndex = 0;
    let offsetHeight = 0;

    for (let i = 0; i < dataSource.length; i++) {
      offsetHeight += getItemHeightFromCache(i);

      if (offsetHeight >= scrollTop) {
        startIndex = i;
        break;
      }
    }

    // 计算得出的渲染数据
    actualRenderData.value = dataSource.slice(
      startIndex,
      startIndex + config.size
    );

    // 缓存最新的列表项高度
    updateRenderedItemCache(startIndex);

    // 更新偏移值
    updateOffset(offsetHeight - getItemHeightFromCache(startIndex));
  };

  // 更新偏移值
  const updateOffset = (offset: number) => {
    translateContainerEl!.style.transform = `translateY(${offset}px)`;
  };

  // 滚动事件
  const handleScroll = (e: any) => {
    // 渲染正确的数据
    updateRenderData(e.target.scrollTop);
  };

  // 注册滚动事件
  onMounted(() => {
    scrollContainerEl?.addEventListener("scroll", handleScroll);
  });

  // 移除滚动事件
  onBeforeUnmount(() => {
    scrollContainerEl?.removeEventListener("scroll", handleScroll);
  });

  return { actualRenderData };
}

 

标签:index,const,hooks,number,let,dataSource,Vue3,封装,config
From: https://www.cnblogs.com/luozhixiang/p/18455910

相关文章

  • 从零搭建Cesium+vue3+vite
    介绍在现代前端开发中,Cesium是一个功能强大的WebGL库,广泛应用于3D地球可视化、空间数据展示等领域。结合Vue3的组件化开发模式,我们可以创建一个高效且可维护的3D地图应用。本文将带你一步步搭建一个简单的Cesium+Vue3项目,并且对各个功能模块进行细致划分,帮助你快......
  • 基于Vue3+pinia+vue-router+axios+element-plus等开发的新闻发布管理系统
    新闻发布管理系统是一个基于Vue3+pinia+vue-router+axios+element-plus等开发的系统,主要功能包括:登录模块、注册模块、新闻分类管理模块、新闻管理模块、个人中心模块(包括基本资料、更换头像、重置密码功能)等。代码下载:源码下载基于Vue3开发的新闻发布管理系统,使用的前端......
  • 组合数与自动取模类(已封装)
    usingi64=longlong;template<classT>constexprTpower(Ta,i64b){Tres=1;for(;b;b/=2,a*=a){if(b%2){res*=a;}}returnres;}constexpri64mul(i64a,i64b,i64p){i64re......
  • 尚硅谷vue3实战项目--硅谷甄选项目笔记
    硅谷甄选运营平台此次教学课程为硅谷甄选运营平台项目,包含运营平台项目模板从0到1开发,以及数据大屏幕、权限等业务。此次教学课程涉及到技术栈包含:vue3+TypeScript+vue-router+pinia+element-plus+axios+echarts等技术栈。一、vue3组件通信方式通信仓库地址:https://gitee.c......
  • 7天毕设速成9小程序接口封装及对接
    1.接口封装1.1.请求接口封装新建文件夹request,新建index.js,封装接口接口调用对应此系列,springboot后端搭建笔记https://blog.csdn.net/PoofeeDong/article/details/140695913代码如下:constcommoneUrl="http://locahost:9999";//对应前面接口//get请求封装functi......
  • 在Vue3中使用vuex
    官方文档vue3+ts一、安装npminstallvuex@next--save二、创建并引入1.新建store文件夹,在store目录下新建index.jsimport{createStore}from'vuex'exportdefaultcreateStore({state:{},mutations:{},actions:{}modules:{}})2.......
  • LED显示驱动/高亮数显屏驱动芯片VK16K33A 采用SOP28封装形式,可支持16SEGx8GRID的点阵L
    VK16K33A是一种带按键扫描接口的数码管或点阵LED驱动控制专用芯片,邱婷:188-2366-8825内部集成有数据锁存器、键盘扫描、LED驱动模块等电路。数据通过I2C通讯接口与MCU通信。SEG脚接LED阳极,GRID脚接LED阴极,可支持16SEGx8GRID的点阵LED显示面板。最大支持13×3的按键。内置上电......
  • vue3中如何实现通用头部?
    在Vue中实现通用头部可以通过以下几种方式:一、使用Vue组件创建头部组件首先,创建一个名为HeaderComponent.vue的Vue组件文件。在这个组件中,可以使用Vue的模板语法来设计头部的结构,例如包含导航栏、品牌标志、搜索框等元素。<template><header><......
  • go抽象封装是一种简化认知的手段
    通过Kubernetes看Go接口设计之道原创 蔡蔡蔡菜 蔡蔡蔡云原生Go  2024年10月01日08:30 广东解耦依赖底层在 Kubernetes 中能看到非常多通过接口对具体实现的封装。Kubelet 实现了非常多复杂的功能,我们可以看到它实现了各种各样的接口,上层代码在使用的时候......
  • vue3 pinia 存数据
    pinia是vue2中的vuex,状态管理,可以实现数据共享1、先安装npminstallpinia 2、在main.ts中进行创建和载入3、在src下新建store文件夹定义存的文件  4、在组件中使用 此时控制台会有具体的值。   ......