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