1 changed files with 238 additions and 0 deletions
@ -0,0 +1,238 @@ |
|||||
|
# HistoryProtocolLogsView 流式加载功能实现 |
||||
|
|
||||
|
## 修改时间 |
||||
|
2025-01-27 |
||||
|
|
||||
|
## 修改文件 |
||||
|
`X1.WebUI/src/pages/protocol-logs/HistoryProtocolLogsView.tsx` |
||||
|
|
||||
|
## 修改目标 |
||||
|
为 HistoryProtocolLogsView 组件添加流式加载(infinite scroll)功能,使用 IntersectionObserver 实现,支持分页加载和用户友好的交互体验。 |
||||
|
|
||||
|
## 修改内容 |
||||
|
|
||||
|
### 1. 组件接口更新 |
||||
|
- 添加 `HistoryProtocolLogsViewProps` 接口,支持可选的 `fetchData` props |
||||
|
- 提供默认的数据获取函数 `defaultFetchData`,保持向后兼容性 |
||||
|
- 使用传入的 `fetchData` 或默认函数进行数据加载 |
||||
|
|
||||
|
### 2. 状态管理增强 |
||||
|
- 添加 `currentPage` 状态管理当前页码 |
||||
|
- 添加 `hasMore` 状态标识是否还有更多数据 |
||||
|
- 添加 `loadingMore` 状态管理加载更多数据的状态 |
||||
|
- 添加 `isInitialLoad` 状态区分初始加载和后续加载 |
||||
|
|
||||
|
### 3. IntersectionObserver 实现 |
||||
|
- 使用 `useRef` 创建观察器引用 `observerRef` |
||||
|
- 使用 `useCallback` 优化 `loadMoreData` 函数 |
||||
|
- 设置观察器选项:`rootMargin: '100px'` 提前100px开始加载 |
||||
|
- 在 `useEffect` 中设置和清理观察器 |
||||
|
|
||||
|
### 4. 数据加载逻辑 |
||||
|
- 实现 `loadMoreData` 函数,处理分页数据加载 |
||||
|
- 支持数据追加:`setProtocolLogs(prev => [...prev, ...newData])` |
||||
|
- 自动更新页码:`setCurrentPage(prev => prev + 1)` |
||||
|
- 检测数据结束:根据返回数据量判断是否还有更多数据 |
||||
|
|
||||
|
### 5. 用户界面优化 |
||||
|
- 添加加载更多提示:显示"加载更多数据..."状态 |
||||
|
- 添加数据结束提示:显示"已加载全部数据" |
||||
|
- 更新记录数显示:包含"滚动加载更多"提示 |
||||
|
- 添加加载状态图标:使用 `Loader2` 组件 |
||||
|
|
||||
|
### 6. 错误处理 |
||||
|
- 完整的错误捕获和用户提示 |
||||
|
- 使用 Toast 组件显示错误信息 |
||||
|
- 保持加载状态的一致性 |
||||
|
|
||||
|
## 技术特性 |
||||
|
|
||||
|
### IntersectionObserver 配置 |
||||
|
```typescript |
||||
|
const observer = new IntersectionObserver( |
||||
|
(entries) => { |
||||
|
const [entry] = entries; |
||||
|
if (entry.isIntersecting && hasMore && !loadingMore) { |
||||
|
loadMoreData(); |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
root: null, |
||||
|
rootMargin: '100px', // 提前100px开始加载 |
||||
|
threshold: 0.1, |
||||
|
} |
||||
|
); |
||||
|
``` |
||||
|
|
||||
|
### 数据加载函数 |
||||
|
```typescript |
||||
|
const loadMoreData = useCallback(async () => { |
||||
|
if (loadingMore || !hasMore) return; |
||||
|
|
||||
|
setLoadingMore(true); |
||||
|
try { |
||||
|
const newData = await fetchDataFunction(currentPage + 1); |
||||
|
|
||||
|
if (newData.length > 0) { |
||||
|
setProtocolLogs(prev => [...prev, ...newData]); |
||||
|
setCurrentPage(prev => prev + 1); |
||||
|
} else { |
||||
|
setHasMore(false); |
||||
|
} |
||||
|
} catch (error) { |
||||
|
// 错误处理 |
||||
|
} finally { |
||||
|
setLoadingMore(false); |
||||
|
} |
||||
|
}, [currentPage, hasMore, loadingMore, fetchDataFunction, toast]); |
||||
|
``` |
||||
|
|
||||
|
### 默认数据获取函数 |
||||
|
```typescript |
||||
|
const defaultFetchData = async (page: number): Promise<ProtocolLogDto[]> => { |
||||
|
const requestParams = { |
||||
|
...searchParams, |
||||
|
page, |
||||
|
pageSize: 20, // 每页20条记录 |
||||
|
}; |
||||
|
|
||||
|
const result = await protocolLogsService.getProtocolLogs(requestParams); |
||||
|
|
||||
|
if (result.isSuccess && result.data) { |
||||
|
return result.data.items || []; |
||||
|
} else { |
||||
|
throw new Error(result.errorMessages?.join(', ') || '获取数据失败'); |
||||
|
} |
||||
|
}; |
||||
|
``` |
||||
|
|
||||
|
## 使用示例 |
||||
|
|
||||
|
### 使用默认数据获取 |
||||
|
```typescript |
||||
|
<HistoryProtocolLogsView /> |
||||
|
``` |
||||
|
|
||||
|
### 使用自定义数据获取函数 |
||||
|
```typescript |
||||
|
<HistoryProtocolLogsView |
||||
|
fetchData={async (page) => { |
||||
|
const result = await customApi.getProtocolLogs({ page, pageSize: 20 }); |
||||
|
return result.data.items || []; |
||||
|
}} |
||||
|
/> |
||||
|
``` |
||||
|
|
||||
|
## 功能效果 |
||||
|
|
||||
|
### 用户体验改进 |
||||
|
- ✅ **平滑滚动加载**:用户滚动到页面底部时自动加载更多数据 |
||||
|
- ✅ **数据追加显示**:新数据追加到现有表格,不会影响现有数据的显示 |
||||
|
- ✅ **加载状态反馈**:提供清晰的加载状态和进度提示 |
||||
|
- ✅ **数据结束提示**:当没有更多数据时显示相应提示 |
||||
|
- ✅ **错误处理**:完整的错误捕获和用户友好的错误提示 |
||||
|
|
||||
|
### 性能优化 |
||||
|
- ✅ **IntersectionObserver**:使用现代浏览器API实现高效的滚动检测 |
||||
|
- ✅ **useCallback 优化**:避免不必要的函数重创建 |
||||
|
- ✅ **useRef 优化**:避免观察器重复创建 |
||||
|
- ✅ **分页加载**:避免一次性加载大量数据导致的性能问题 |
||||
|
|
||||
|
### 向后兼容性 |
||||
|
- ✅ **可选 props**:`fetchData` 为可选参数,不影响现有使用 |
||||
|
- ✅ **默认行为**:保持原有的数据获取逻辑 |
||||
|
- ✅ **接口兼容**:不破坏现有的组件接口 |
||||
|
|
||||
|
## 技术实现细节 |
||||
|
|
||||
|
### 观察器生命周期管理 |
||||
|
```typescript |
||||
|
useEffect(() => { |
||||
|
if (!observerRef.current) return; |
||||
|
|
||||
|
observer.current = new IntersectionObserver(/* ... */); |
||||
|
observer.current.observe(observerRef.current); |
||||
|
|
||||
|
return () => { |
||||
|
if (observer.current) { |
||||
|
observer.current.disconnect(); |
||||
|
} |
||||
|
}; |
||||
|
}, [loadMoreData, hasMore, loadingMore]); |
||||
|
``` |
||||
|
|
||||
|
### 状态重置逻辑 |
||||
|
```typescript |
||||
|
const fetchProtocolLogs = async (params: GetProtocolLogsRequest = searchParams) => { |
||||
|
setLoading(true); |
||||
|
setIsInitialLoad(true); |
||||
|
setCurrentPage(1); |
||||
|
setHasMore(true); |
||||
|
|
||||
|
// ... 数据加载逻辑 |
||||
|
}; |
||||
|
``` |
||||
|
|
||||
|
### 用户界面元素 |
||||
|
```typescript |
||||
|
{/* 无限滚动观察器 */} |
||||
|
{hasMore && ( |
||||
|
<div ref={observerRef} className="flex justify-center items-center py-4"> |
||||
|
{loadingMore && ( |
||||
|
<div className="flex items-center gap-2 text-sm text-muted-foreground"> |
||||
|
<Loader2 className="h-4 w-4 animate-spin" /> |
||||
|
加载更多数据... |
||||
|
</div> |
||||
|
)} |
||||
|
</div> |
||||
|
)} |
||||
|
|
||||
|
{/* 没有更多数据的提示 */} |
||||
|
{!hasMore && protocolLogs.length > 0 && !isInitialLoad && ( |
||||
|
<div className="flex justify-center items-center py-4"> |
||||
|
<span className="text-sm text-muted-foreground"> |
||||
|
已加载全部数据 |
||||
|
</span> |
||||
|
</div> |
||||
|
)} |
||||
|
``` |
||||
|
|
||||
|
## 测试建议 |
||||
|
|
||||
|
### 功能测试 |
||||
|
1. **基本滚动加载**:测试滚动到底部时是否自动加载更多数据 |
||||
|
2. **数据追加**:验证新数据是否正确追加到现有表格 |
||||
|
3. **加载状态**:检查加载状态是否正确显示和隐藏 |
||||
|
4. **数据结束**:测试当没有更多数据时的提示显示 |
||||
|
5. **错误处理**:测试网络错误时的错误提示 |
||||
|
|
||||
|
### 性能测试 |
||||
|
1. **大量数据**:测试加载大量数据时的性能表现 |
||||
|
2. **内存使用**:检查长时间使用时的内存占用 |
||||
|
3. **滚动性能**:验证滚动时的流畅度 |
||||
|
|
||||
|
### 兼容性测试 |
||||
|
1. **浏览器兼容性**:测试不同浏览器对 IntersectionObserver 的支持 |
||||
|
2. **移动端适配**:验证在移动设备上的使用体验 |
||||
|
3. **响应式设计**:测试不同屏幕尺寸下的显示效果 |
||||
|
|
||||
|
## 后续优化建议 |
||||
|
|
||||
|
### 可能的改进方向 |
||||
|
1. **虚拟滚动**:对于超大数据量,考虑实现虚拟滚动 |
||||
|
2. **缓存机制**:添加数据缓存,避免重复加载 |
||||
|
3. **预加载**:实现预加载机制,提前加载下一页数据 |
||||
|
4. **搜索重置**:搜索时重置分页状态 |
||||
|
5. **加载动画**:添加更丰富的加载动画效果 |
||||
|
|
||||
|
### 监控指标 |
||||
|
1. **加载成功率**:监控数据加载的成功率 |
||||
|
2. **加载时间**:监控每次加载的耗时 |
||||
|
3. **用户行为**:监控用户的滚动和加载行为 |
||||
|
4. **错误率**:监控加载错误的频率 |
||||
|
|
||||
|
## 总结 |
||||
|
|
||||
|
本次修改成功为 HistoryProtocolLogsView 组件添加了流式加载功能,提供了良好的用户体验和性能表现。实现采用了现代的 IntersectionObserver API,确保了高效的滚动检测和流畅的用户交互。同时保持了向后兼容性,不影响现有功能的使用。 |
||||
|
|
||||
|
该实现为后续的大数据量展示需求提供了良好的基础,可以根据实际使用情况进行进一步的优化和扩展。 |
||||
Loading…
Reference in new issue