# CrossPageSelection - 跨页全选功能 ## 📖 概述 跨页全选是列表页面中的常见需求,当数据量较大且分页显示时,用户可能需要选择所有数据而不仅仅是当前页的数据。本功能提供了一套完整的跨页全选解决方案,包括: - **ListActionBar 扩展** - 选择信息显示和全选操作 - **ListTable 扩展** - 跨页全选状态支持 ## 🎯 设计方案 ### 设计理念 将选择信息和全选操作集成到操作栏(ListActionBar),分页器只显示分页信息,保持功能职责清晰分离。 ### 交互流程 ``` 1. 用户勾选当前页或部分数据 ↓ 2. 操作栏显示:"已选择 5 项 [选择全部 100 项] [清除]" ↓ 3. 用户点击"选择全部 100 项" ↓ 4. 设置 isAllPagesSelected = true ↓ 5. selectedRowKeys 包含所有数据的 key ↓ 6. 操作栏更新:"已选择 100 项(全部页) [清除]" ↓ 7. 执行批量操作(删除、导出等) ``` ### 操作栏显示逻辑 | 选择状态 | 操作栏显示 | |---------|-----------| | 无选中 | [新建] 按钮 | | 选中部分(< 总数) | "已选择 5 项 [选择全部 100 项] [清除]" + 批量操作按钮 | | 跨页全选 | "已选择 100 项(全部页) [清除]" + 批量操作按钮 | ## 📦 核心功能 ### 1. ListActionBar - 操作栏扩展(核心) #### 新增功能 在原有 ListActionBar 的基础上,新增了批量操作区域: - 当有选中项时,隐藏常规操作按钮,显示批量操作区域 - 显示选中信息(数量、是否跨页全选) - 提供快捷的"选择全部"和"清除"链接 - 显示批量操作按钮(批量编辑、批量删除等) #### 新增 Props | 参数 | 说明 | 类型 | 默认值 | |------|------|------|--------| | batchActions | 批量操作按钮配置数组 | Array<Action> | [] | | selectionInfo | 选中信息对象 | SelectionInfo | null | | onSelectAllPages | 选择所有页回调 | function | - | | onClearSelection | 清除选择回调 | function | - | #### SelectionInfo 对象 ```typescript { count: number, // 选中数量 total: number, // 总数据量 isAllPagesSelected: boolean // 是否跨页全选 } ``` #### Action 配置 ```typescript { key: string, // 唯一标识 label: string, // 按钮文本 type?: string, // 按钮类型:default | primary | dashed | link | text icon?: ReactNode, // 图标 disabled?: boolean, // 是否禁用 danger?: boolean, // 危险按钮样式 onClick: function // 点击回调 } ``` #### 使用示例 ```jsx import ListActionBar from '../components/ListActionBar/ListActionBar' import { DeleteOutlined, ExportOutlined, EditOutlined } from '@ant-design/icons' , onClick: handleAdd, }, ]} // 批量操作按钮(有选中时显示) batchActions={[ { key: 'edit', label: '批量编辑', icon: , onClick: handleBatchEdit, }, { key: 'export', label: '批量导出', icon: , onClick: handleBatchExport, }, { key: 'delete', label: '批量删除', icon: , danger: true, onClick: handleBatchDelete, }, ]} // 选中信息 selectionInfo={ selectedRowKeys.length > 0 ? { count: selectedRowKeys.length, total: totalCount, isAllPagesSelected: isAllPagesSelected, } : null } onSelectAllPages={handleSelectAllPages} onClearSelection={handleClearSelection} // 其他原有配置... search={{ ... }} showRefresh onRefresh={handleRefresh} /> ``` --- ### 2. ListTable - 表格扩展(分页器集成全选) #### 新增功能 支持跨页全选状态的显示: - 当 `isAllPagesSelected=true` 时,所有行显示为选中状态 - 自定义表头全选框,显示"全选"标识 - 禁用单个 checkbox,防止用户取消选择(需通过"清除选择"统一取消) #### 新增 Props | 参数 | 说明 | 类型 | 默认值 | |------|------|------|--------| | isAllPagesSelected | 是否跨页全选所有数据 | boolean | false | | totalCount | 总数据量 | number | - | #### 使用示例(重点:自定义 showTotal) ```jsx import ListTable from '../components/ListTable/ListTable' { // 如果有选中项,显示选择信息和全选操作 if (selectedRowKeys.length > 0) { if (isAllPagesSelected) { return ( 已选择全部 {total} 条数据 清除选择 ) } else if (selectedRowKeys.length < total) { return ( 已选择 {selectedRowKeys.length} 条数据 选择全部 {total} 条 清除 ) } else { return ( 已选择全部 {total} 条数据 清除选择 ) } } // 无选中项时,显示常规的分页信息 return `共 ${total} 条` }, onChange: (page, size) => { setCurrentPage(page) setPageSize(size) }, }} /> ``` #### 分页器样式 ```css /* 分页器中的选择信息样式 */ .pagination-selection-info { color: rgba(0, 0, 0, 0.85); font-size: 14px; } .pagination-selection-info strong { color: #1677ff; font-weight: 600; margin: 0 4px; } .pagination-selection-info a { color: #1677ff; cursor: pointer; text-decoration: none; transition: all 0.2s; } .pagination-selection-info a:hover { text-decoration: underline; } ``` ## 🚀 完整使用示例 ### 状态管理 ```jsx import { useState } from 'react' function MyListPage() { // 数据源(实际项目中通常从 API 获取) const [dataSource] = useState([...]) // 所有数据 const [totalCount] = useState(dataSource.length) // 分页状态 const [currentPage, setCurrentPage] = useState(1) const [pageSize, setPageSize] = useState(10) // 选择状态 const [selectedRowKeys, setSelectedRowKeys] = useState([]) const [isAllPagesSelected, setIsAllPagesSelected] = useState(false) // 当前页数据 const currentPageData = useMemo(() => { const start = (currentPage - 1) * pageSize const end = start + pageSize return dataSource.slice(start, end) }, [dataSource, currentPage, pageSize]) // ... 处理函数 } ``` ### 核心处理函数 ```jsx // 选择变化处理(重要:支持跨页选择) const handleSelectionChange = (keys) => { // keys 是当前页面操作后的选中项 // 需要合并其他页的选中项,以保持跨页选择状态 const currentPageKeys = currentPageData.map(item => item.id) const otherPagesSelectedKeys = selectedRowKeys.filter(key => !currentPageKeys.includes(key)) const newSelectedKeys = [...otherPagesSelectedKeys, ...keys] setSelectedRowKeys(newSelectedKeys) setIsAllPagesSelected(false) } // 选择所有页 const handleSelectAllPages = () => { setIsAllPagesSelected(true) setSelectedRowKeys(dataSource.map(item => item.id)) // 设置所有数据的 key message.success(`已选择全部 ${totalCount} 条数据`) } // 清除选择 const handleClearSelection = () => { setSelectedRowKeys([]) setIsAllPagesSelected(false) message.info('已清除选择') } // 批量删除 const handleBatchDelete = () => { Modal.confirm({ title: '确认删除', content: isAllPagesSelected ? `确定要删除全部 ${totalCount} 条数据吗?` : `确定要删除选中的 ${selectedRowKeys.length} 条数据吗?`, onOk: () => { // 执行删除逻辑 if (isAllPagesSelected) { // 删除所有数据 } else { // 删除选中的数据:selectedRowKeys } handleClearSelection() }, }) } ``` ### 页面结构 ```jsx return (
{/* 操作栏 - 显示选择信息和全选操作 */} 0 ? { count: selectedRowKeys.length, total: totalCount, isAllPagesSelected, } : null } onSelectAllPages={handleSelectAllPages} onClearSelection={handleClearSelection} search={...} /> {/* 列表表格 - 分页器只显示分页信息 */} `共 ${total} 条`, }} />
) ``` ## 💡 最佳实践 ### 0. 跨页选择的实现要点(重要!) 由于 Table 组件只接收当前页数据(`currentPageData`),需要手动维护跨页的选中状态: ```jsx const handleSelectionChange = (keys) => { // ❌ 错误做法:直接替换会丢失其他页的选择 // setSelectedRowKeys(keys) // ✅ 正确做法:合并其他页的选择 const currentPageKeys = currentPageData.map(item => item.id) const otherPagesSelectedKeys = selectedRowKeys.filter(key => !currentPageKeys.includes(key)) const newSelectedKeys = [...otherPagesSelectedKeys, ...keys] setSelectedRowKeys(newSelectedKeys) setIsAllPagesSelected(false) } ``` **工作原理**: 1. `currentPageKeys` - 当前页所有数据的 key 列表 2. `otherPagesSelectedKeys` - 从已选项中过滤出不在当前页的 keys(即其他页的选择) 3. `newSelectedKeys` - 合并其他页的选择 + 当前页的新选择 4. 这样就保持了所有页的选中状态 ### 1. 批量操作提示 执行批量操作时,明确提示操作范围: ```jsx const handleBatchDelete = () => { const count = isAllPagesSelected ? totalCount : selectedRowKeys.length const scope = isAllPagesSelected ? '全部' : '选中的' Modal.confirm({ title: '确认删除', content: `确定要删除${scope} ${count} 条数据吗?此操作不可恢复。`, okText: '确定', cancelText: '取消', okButtonProps: { danger: true }, onOk: async () => { try { if (isAllPagesSelected) { await deleteAll() } else { await deleteByIds(selectedRowKeys) } message.success('删除成功') handleClearSelection() refreshData() } catch (error) { message.error('删除失败:' + error.message) } }, }) } ``` ### 2. 分页切换时的选择状态 根据业务需求,可以选择两种策略: **策略 A:保持选择状态**(推荐) ```jsx // 切换分页时,保持已选择的数据 const handlePageChange = (page, size) => { setCurrentPage(page) setPageSize(size) // 不清除 selectedRowKeys,保持选择状态 } ``` **策略 B:清除选择状态** ```jsx // 切换分页时,清除选择 const handlePageChange = (page, size) => { setCurrentPage(page) setPageSize(size) handleClearSelection() // 清除选择 } ``` ### 3. 后端 API 对接 跨页全选时,后端 API 应支持两种方式: ```jsx // 方式1:发送所有选中的 ID(推荐小数据量) const handleBatchOperation = async () => { await api.batchOperation({ ids: selectedRowKeys, // 所有选中的 ID }) } // 方式2:发送全选标识 + 筛选条件(推荐大数据量) const handleBatchOperation = async () => { await api.batchOperation({ selectAll: isAllPagesSelected, filters: currentFilters, // 当前筛选条件 excludeIds: [], // 排除的 ID(如果有反选功能) }) } ``` ### 4. 性能优化 当数据量很大时(如超过 10000 条),避免一次性加载所有 ID: ```jsx const handleSelectAllPages = () => { setIsAllPagesSelected(true) // 不要: setSelectedRowKeys(dataSource.map(item => item.id)) // 太多 ID 会导致性能问题 // 推荐: 只标记状态,实际操作时由后端根据筛选条件处理 message.success(`已选择全部数据`) } const handleBatchDelete = async () => { if (isAllPagesSelected) { // 发送全选标识和筛选条件,由后端处理 await api.deleteAll({ filters: currentFilters }) } else { // 发送具体的 ID 列表 await api.deleteByIds(selectedRowKeys) } } ``` ## 📝 注意事项 1. **全选状态的一致性** - 手动勾选/取消勾选时,应取消跨页全选状态 - 确保 `selectedRowKeys` 和 `isAllPagesSelected` 状态同步 2. **筛选和搜索** - 执行筛选或搜索后,应清除选择状态 - 或者保持选择,但提示用户"选择的数据可能不在当前筛选结果中" 3. **数据刷新** - 刷新数据后,应重新评估选择状态的有效性 - 建议清除选择,或检查已选数据是否仍然存在 4. **权限控制** - 批量操作应检查权限 - 跨页全选时,应提示可能操作大量数据 ## 🎨 样式定制 ### ListActionBar 批量操作区样式定制 ```css /* 修改选中信息区域背景色 */ .selection-info { background: #f0f9ff; border-color: #69b1ff; } /* 修改选中数量颜色 */ .selection-count strong { color: #ff4d4f; } /* 修改全部页标识颜色 */ .all-pages-tag { color: #ff4d4f; } /* 修改链接颜色 */ .select-all-link, .clear-selection-link { color: #52c41a; } ``` ## 🔗 相关组件 - [ListTable](./ListTable.md) - 列表表格组件 - [ListActionBar](./ListActionBar.md) - 列表���作栏组件 - [PageTitleBar](./PageTitleBar.md) - 页面标题栏组件 ## 📚 参考资料 - [Ant Design Table 组件](https://ant.design/components/table-cn/) - [Ant Design Pagination 组件](https://ant.design/components/pagination-cn/) --- **更新日志** - v1.2.0 (2025-11-18) - ♻️ 重构设计:将全选功能集成到操作栏,分页器只显示分页信息 - ✨ 更清晰的职责分离:操作相关在操作栏,分页相关在分页器 - 📝 更新文档和使用示例 - v1.1.0 (2025-11-18) - ♻️ 重构设计:将全选功能集成到分页器,移除独立的 SelectionAlert 组件 - ✨ 更简洁的交互:选择信息、全选操作、分页控制集中在一个区域 - 📝 更新文档和使用示例 - v1.0.0 (2025-11-18) - ✨ 新增 SelectionAlert 组件 - ✨ 扩展 ListActionBar 支持批量操作 - ✨ 扩展 ListTable 支持跨页全选状态 - 📝 完善文档和使用示例