feat: 创建无限滚动Hook │ │
│ │ │ │ │ │ - 监听容器滚动事件 │ │ │ │ - 距离底部阈值可配置(默认200px) │ │ │ │ - 自动触发onLoadMore回调 │ │ │ │ - 支持加载状态管理
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
// src/views/Community/components/DynamicNewsCard/hooks/useInfiniteScroll.js
|
||||
// 无限滚动 Hook
|
||||
|
||||
import { useEffect, useRef, useCallback } from 'react';
|
||||
|
||||
/**
|
||||
* 无限滚动 Hook
|
||||
* 监听容器滚动事件,当滚动到底部附近时触发加载更多数据
|
||||
*
|
||||
* @param {Object} options - 配置选项
|
||||
* @param {Function} options.onLoadMore - 加载更多回调函数(返回 Promise)
|
||||
* @param {boolean} options.hasMore - 是否还有更多数据
|
||||
* @param {boolean} options.isLoading - 是否正在加载
|
||||
* @param {number} options.threshold - 触发阈值(距离底部多少像素时触发,默认200px)
|
||||
* @returns {Object} { containerRef } - 容器引用
|
||||
*/
|
||||
export const useInfiniteScroll = ({
|
||||
onLoadMore,
|
||||
hasMore = true,
|
||||
isLoading = false,
|
||||
threshold = 200
|
||||
}) => {
|
||||
const containerRef = useRef(null);
|
||||
const isLoadingRef = useRef(false);
|
||||
|
||||
// 滚动处理函数
|
||||
const handleScroll = useCallback(() => {
|
||||
const container = containerRef.current;
|
||||
|
||||
// 检查条件:容器存在、未加载中、还有更多数据
|
||||
if (!container || isLoadingRef.current || !hasMore) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { scrollTop, scrollHeight, clientHeight } = container;
|
||||
const distanceToBottom = scrollHeight - scrollTop - clientHeight;
|
||||
|
||||
// 距离底部小于阈值时触发加载
|
||||
if (distanceToBottom < threshold) {
|
||||
console.log(
|
||||
'%c⬇️ [懒加载] 触发加载下一页',
|
||||
'color: #8B5CF6; font-weight: bold;',
|
||||
{
|
||||
scrollTop,
|
||||
scrollHeight,
|
||||
clientHeight,
|
||||
distanceToBottom,
|
||||
threshold
|
||||
}
|
||||
);
|
||||
|
||||
isLoadingRef.current = true;
|
||||
|
||||
// 调用加载函数并更新状态
|
||||
onLoadMore()
|
||||
.then(() => {
|
||||
console.log('%c✅ [懒加载] 加载完成', 'color: #10B981; font-weight: bold;');
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('%c❌ [懒加载] 加载失败', 'color: #DC2626; font-weight: bold;', error);
|
||||
})
|
||||
.finally(() => {
|
||||
isLoadingRef.current = false;
|
||||
});
|
||||
}
|
||||
}, [onLoadMore, hasMore, threshold]);
|
||||
|
||||
// 绑定滚动事件
|
||||
useEffect(() => {
|
||||
const container = containerRef.current;
|
||||
if (!container) return;
|
||||
|
||||
// 添加滚动监听
|
||||
container.addEventListener('scroll', handleScroll, { passive: true });
|
||||
|
||||
// 清理函数
|
||||
return () => {
|
||||
container.removeEventListener('scroll', handleScroll);
|
||||
};
|
||||
}, [handleScroll]);
|
||||
|
||||
// 更新 loading 状态的 ref
|
||||
useEffect(() => {
|
||||
isLoadingRef.current = isLoading;
|
||||
}, [isLoading]);
|
||||
|
||||
return { containerRef };
|
||||
};
|
||||
Reference in New Issue
Block a user