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