Vue3 自定义滚动加载Hook

89 阅读1分钟

前言

基于vue3 在web端实现一个滚动加载更多数据, 自己简单写了一个hook记录以及分享一下。

1、代码如下:

export const useScrollLoad = params => {
  try {
    const { isReady, className, apiFetch, afterLoadPage } = unref(params) || {};
    const dataSourse = ref<any>([]);
    const immediate = ref(!!isReady);
    let oldScrollTop = 0; // 记录上一次滚动的位置
    let listenDom;
    onMounted(() => {
      console.log('0000--');
      immediate && onLoadPage();
      init(); // 注册滚动监听
    });
    // 初始化
    const init = () => {
      // 注册当前容器的滚动监听
      nextTick(() => {
        listenDom = document.getElementsByClassName(className)[0];
        listenDom?.addEventListener('scroll', listenScroll);
      });
    };
    // 加载数据
    const onLoadPage = async () => {
      try {
        const { code, data } = await apiFetch(unref(params).queryData);
        if (code == 200) {
          const { records } = data;
          if (!records.length && unref(params).queryData.current > 1) {
            // message.warning('没有更多数据了');
            return;
          }
          unref(params).queryData.current++;
          dataSourse.value.push(...(records || []));
          afterLoadPage && afterLoadPage(dataSourse.value);
        }
      } catch (error) {
        console.log(error);
      }
    };
    // 重置加载
    const resetLoadPage = () => {
      dataSourse.value = [];
      unref(params).queryData.current = 1;
      onLoadPage();
    };
    const listenScroll = (e: Event): void => {
      if (unref(params).queryData.current === 1 && !dataSourse.value.length) {
        return;
      }
      const target = e.target as EventTarget & HTMLDivElement;
      const scrollTop = Math.ceil(target?.scrollTop); // 距顶部距离
      const clientHeight = Math.ceil(target?.clientHeight); // 可视区高度
      const scrollHeight = Math.ceil(target?.scrollHeight); // 滚动条总高度
      // 考虑到滚动的位置一般可能会大于一点可滚动的高度,所以这里不能用等于
      // 对比oldScrollTop 与 scrollTop的值,如果相等,说明滚动条没有滚动,直接return
      if (oldScrollTop === scrollTop) {
        return;
      }
      oldScrollTop = scrollTop;
      if (scrollTop && scrollTop + clientHeight >= scrollHeight) {
        onLoadPage && onLoadPage();
      }
    };
    // 卸载
    onUnmounted(() => {
      if (listenDom) {
        listenDom.scrollTop = 0;
        listenDom?.removeEventListener('scroll', listenScroll);
      }
    });

    return {
      dataSourse,
      resetLoadPage,
    };
  } catch (error) {
    console.error(error);
  }
};

2、使用方式:

// api
import { postDemoPage } from '@/api/demo-api';
// 滚动加载
import { useScrollLoad } from '@/hooks/useScrollLoad';
// 滚动加载参数配置
const params = ref({
  className: 'content',
  queryData: {
    current: 1,
    size: 10,
    searchKey: '',
    typeList: [],
    updateTimeStart: undefined,
    updateTimeEnd: undefined,
  },
  apiFetch: postDemoPage,
});
const { dataSourse, resetLoadPage } = useScrollLoad(params); // 滚动加载