Vue3滚动加载(懒加载)

滚动加载Hooks,一般用于数据量较大的列表滚动,对于大数据量渲染优化处理不仅仅只有滚动加载,还可以采用虚拟滚动,关注博主,后续带给你更多的高质量博客~

Hooks useLazyLoad

interface UseLazyLoadQo<T> {
    
    
  className: string; // 监听的dom的class
  calcBottomCount: number; // 计算滚动到table底部的次数
  data: T[]; // 数据
  getData: () => void | Promise<void>; // 获取数据的方法
}

interface UseLazyLoadVo<T> {
    
    
  updateData?: (nextData: T[]) => void;
}

export const useLazyLoad = <T>(params: UseLazyLoadQo<T>): UseLazyLoadVo<T> => {
    
    
  try {
    
    
    const {
    
     className, data, getData, calcBottomCount } = params || {
    
    };
    let list = data;
    let oldScrollTop = 0; // 记录上一次滚动的位置
    let listenDom;

    onMounted(() => {
    
    
      listenDom = document.getElementsByClassName(className)[0];
      console.log("mounted", listenDom);
      listenDom?.addEventListener("scroll", listenScroll);
    });

    const updateData = (nextData: T[]): void => {
    
    
      list = nextData;
    };

    const listenScroll = (e: Event): void => {
    
    
      if (calcBottomCount === 1 && !list.length) return;
      const target = e.target as EventTarget & HTMLDivElement;
      // js有精度问题,所以要向上取整
      const scrollTop = Math.ceil(target?.scrollTop); // 距顶部距离
      const clientHeight = Math.ceil(target?.clientHeight); // 可视区高度
      const scrollHeight = Math.ceil(target?.scrollHeight); // 滚动条总高度
      // 考虑到滚动的位置一般可能会大于一点可滚动的高度,所以这里不能用等于
      // 对比oldScrollTop 与 scrollTop的值,如果相等,说明滚动条没有滚动,直接return
      // console.log('scrollTop', scrollTop, 'clientHeight', clientHeight, 'scrollHeight', scrollHeight);
      if (oldScrollTop === scrollTop) return;
      oldScrollTop = scrollTop;
      if (scrollTop && scrollTop + clientHeight >= scrollHeight) {
    
    
        getData && getData();
      }
    };

    onUnmounted(() => {
    
    
      removeEventListener("scroll", listenScroll);
    });

    return {
    
    
      updateData, // 更新数据
    };
  } catch (error) {
    
    
    console.error(error);
    return {
    
    
      updateData: undefined,
    };
  }
};

使用:

interface MyState {
    
    
  appData: any[];
}
const state = reactive<MyState>({
    
    
  appData: [],
});
let calcBottomCount = 1; // 计算滚动到table底部的次数(滚动到底部加 1 如果没有数据 就不赋值)

const params = {
    
    
  className: 'app-wrap_view',
  data: state.appData,
  getData: getData,
  calcBottomCount,
};

const {
    
     updateData } = useLazyLoad<pageListVO>(params);

watch(
  () => state.appData,
  () => {
    
    
    // 由于 useLazyLoad 无法监听数据变化,所以需在watch中调用函数
    updateData && updateData(state.appData);
  }
);

const getData = async (): Promise<void> => {
    
    
  try {
    
    
    const params: pageListQO = {
    
    
      current: calcBottomCount,
      productName: '',
      size: 20,
    };
    state.loading = true;
    const res = await xxApi(params);
    state.loading = false;
    
    const {
    
     code } = res || {
    
    };
    if (code !== RES_CODE.SUCCESS) return;
    const {
    
     list } = res.data || {
    
    };
    if (!list.length && calcBottomCount > 1) {
    
    
      message.warning('没有更多数据了');
      return;
    }
    calcBottomCount++;
    state.appData.push(...(list || []));
  } catch (error) {
    
    
    state.loading = false;
    console.error(error);
  }
};

猜你喜欢

转载自blog.csdn.net/Cavin80/article/details/128935364