- Published on
React 项目开发 小记
- Authors
- Name
- KingCwt
- @kingcwtcool
1. 列表页面跳转详情页 点击返回列表页 保存 列表参数和分页 【仅供参考】
假如 列表页和详情页面长这样



需求:
点击查看后 保存列表的搜索参数和分页选择
注意1: 复制详情页面地址 点击返回列表页 还原列表参数和分页
注意2: 点击返回列表页面 保存参数后 这个时候再次点击查看操作 跳转详情 再返回列表页面 也是上一步状态
注意3: 我刷新列表页面 还原最初的进列表页面的状态
好,开始实现
首先第一步 不管搜索,分页 都要存在一状态里面,如果搜索变化或者分页变化 只会修改状态。然后监听状态的变化,除非请求后端接口数据
首先 定义分页和搜索参数的状态 还要定义一个ref存数据,因为在antd中点击操作 有些情况下不会拿到最新的状态 所以这里使用ref
interface PageParamsType {
templateId?: number // 选择的模板
writeStatus?: string // 处理状态
reportName?: string // 搜索的文档名称
pageNo: number // 分页
pageSize: number // 页数
}
// 定义 搜索需要的状态
const [pageParams, setPageParams] = useState<PageParamsType>({ pageNo: 1, pageSize: 10 })
// 把状态存在pageParamsRef中 因为有些情况下 状态不会拿到最新的 所以使用ref
const pageParamsRef = useRef<PageParamsType>({ pageNo: 1, pageSize: 10 })
参考搜索方法的代码
// 搜索方法代码
// 我们设置更新 setPageParams
const handleSearch = (value: string, type: string) => {
const { writeStatus } = searchForm.getFieldsValue()
const params: Omit<GetDBDocumentParamsType, 'pageNo' | 'pageSize'> = {}
const formItem = searchForm.getFieldsValue()
if (writeStatus) {
params.writeStatus = writeStatus
pageParamsRef.current.writeStatus = writeStatus
} else {
delete params.writeStatus
const newPam = { ...pageParamsRef.current }
delete newPam.writeStatus
pageParamsRef.current = newPam
}
if (formItem?.templateId) {
pageParamsRef.current.templateId = formItem?.templateId
params.templateId = formItem?.templateId
} else {
delete params.templateId
const newPam = { ...pageParamsRef.current }
delete newPam.templateId
pageParamsRef.current = newPam
}
if (id) {
params.projectId = Number(id)
}
if (type === 'search') {
params.reportName = value
} else {
params.reportName = searchValue
}
pageParamsRef.current.reportName = params.reportName
pageParamsRef.current.pageNo = 1
pageParamsRef.current.pageSize = 10
setPageParams({ pageNo: 1, pageSize: 10, ...params })
}
然后是分页操作方法
// 同样是更新 setPageParams
const pageChange = (page: number, pageSize: number) => {
pageParamsRef.current.pageNo = page
pageParamsRef.current.pageSize = pageSize
setPageParams({ ...pageParams, pageNo: page, pageSize })
}
ok,接下来是定义状态更新 请求后端接口
import { useRequest } from 'ahooks'
import { getDBDocument } from '@/services/bondUnderwriting.service'
const { data, error, loading, run } = useRequest(getDBDocument, {
manual: true,
pollingInterval: 5000,
loadingDelay: 5000,
})
useEffect(() => {
if (id) {
// 这里当搜索或者分页触发是 状态变化 请求后端接口
run({ projectId: Number(id), ...pageParams })
// 同样存到ref中
pageParamsRef.current = { ...pageParams }
}
}, [id, pageParams])
然后 就是列表页面的查看操作方法啦。
import { useLocation, useNavigate, useParams, useSearchParams } from 'react-router-dom'
const navigator = useNavigate()
const location = useLocation()
// 然后这里 跳转详情 把ref的值 存到地址栏中 这里其实有个缺陷 就是如果数据太长 会有丢失问题哦。【要注意】
const onView = (item: GetDBDocumentListType) => {
const state = { ...pageParamsRef.current, from: location.pathname + location.search }
navigator(`/document/detail/${item.fileId}/${item.id}/edit?writeStatus=${item.writeStatus}&groupId=${item.groupId}&state=${encodeURIComponent(JSON.stringify(state))}`)
}
接下来是 详情页面 点击返回操作的代码
import { useNavigate, useSearchParams } from 'react-router-dom'
const [searchparams] = useSearchParams()
const stateStr = searchparams.get('state')
// OK 这里点击返回 把地址参数转换 然后跳转到列表页面
const onComeBack = () => {
if (stateStr) {
const state = JSON.parse(decodeURIComponent(stateStr))
navigator(state.from, { state })
}
}
最后,我们在列表页面接受详情页面传过来保存的状态
import { useLocation, useNavigate, useParams, useSearchParams } from 'react-router-dom'
const location = useLocation()
const { id, menuType } = useParams()
// id这里不用管,给实现无关
// 然后我们通过location,拿到保存的状态 然后设置 比如左侧的搜索 我这里是Form表单 所以直接通过setFieldsValue设置 模板id,状态下拉的值,然后搜索的值是状态,这里setSearchValue
useEffect(() => {
if (id) {
if (location.state) {
const newObj = { ...location.state }
delete newObj.from
// 设置保存
setPageParams({ pageNo: 1, pageSize: 10, ...newObj })
// 然后这里清空跳转state,下次刷新将是初始化的状态
navigator(location.pathname, { replace: true, state: {} })
}
if (location.state.templateId) {
searchForm.setFieldsValue({
templateId: location.state.templateId,
})
}
if (location.state.writeStatus) {
searchForm.setFieldsValue({
writeStatus: location.state.writeStatus,
})
}
setSearchValue(location.state.reportName || '')
}
}, [])
2. 实现表格复制和文本复制 【仅供参考】
// 复制表格
function copyTableWithStyle(id:string) {
const table: any = document.querySelector(`.className_${id}`)
// 创建一个新的div来存放表格
const container = document.createElement('div')
// 克隆表格并保留所有样式
const tableClone = table.cloneNode(true)
// 获取原表格的计算样式并应用
const computedStyle = window.getComputedStyle(table)
tableClone.style.cssText = computedStyle.cssText
// 复制所有单元格的样式
const originalCells = table.querySelectorAll('th, td')
const clonedCells = tableClone.querySelectorAll('th, td')
originalCells.forEach((cell: any, index: number) => {
const computedCellStyle = window.getComputedStyle(cell)
clonedCells[index].style.cssText = computedCellStyle.cssText
})
// 复制所有行的样式
const originalRows = table.querySelectorAll('tr')
const clonedRows = tableClone.querySelectorAll('tr')
originalRows.forEach((row: any, index: number) => {
const computedRowStyle = window.getComputedStyle(row)
clonedRows[index].style.cssText = computedRowStyle.cssText
})
container.appendChild(tableClone)
// 将容器添加到文档中(设置为不可见)
container.style.position = 'fixed'
container.style.left = '-9999px'
container.style.top = '0'
document.body.appendChild(container)
// 选择内容
const range = document.createRange()
range.selectNode(container)
const selection = window.getSelection()
selection!.removeAllRanges()
selection!.addRange(range)
try {
// 执行复制命令
const successful = document.execCommand('copy')
if (successful) {
message.success('表格已复制到剪贴板')
} else {
message.success('复制失败')
}
} catch (err) {
message.error('复制出错:', err as any)
}
// 清理
selection!.removeAllRanges()
document.body.removeChild(container)
}
// # 复制文本
const onProcessingText = (item: any) => {
if (navigator.clipboard) {
console.log('in navigator.clipboard')
message.success('已复制数据至剪贴板')
return navigator.clipboard.writeText(item.materialData) // 要复制的内容 item.materialData
}
const input = document.createElement('input')
input.setAttribute('value', item.materialData)
document.body.appendChild(input)
input.select()
try {
document.execCommand('copy')
message.success('复制成功')
} catch (err) {
message.error('复制失败', err as any)
}
document.body.removeChild(input)
}
// main
const onCopy = async (item: any, id: any) => {
// 表格
if (item.materialType === 'table') {
copyTableWithStyle(id)
} else {
// 文本
onProcessingText(item)
}
}