滚动加载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);
}
};