前言
基于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); // 滚动加载