需求
提供100位用户信息。其用户信息含:{ id: 1, age: 42, name: '张小强', address: "北京" },
;
要求1:需要设计可以多选择来筛选得到指点条件用户表,可以选择=>各阶段年龄端或者不同地区的。选择的条件,可以清空;
要求2: 选择的条件,需要在页面路由上呈现;方便其他用户copy,可以查询到一样的结果;
实例
网页实现
实现
需要提前下载相关依赖哈,nanoid
import React, { Fragment, useEffect, useState } from 'react'
import { useNavigate, useSearchParams } from 'react-router-dom'
import { nanoid } from 'nanoid'
import "./tableStyle.css"
export default function ShoppingMall(props) {
const users = [
{
id: nanoid(),
age: 42,
name: '张小强',
address: "北京"
},
{
id: nanoid(),
age: 12,
name: '明明',
address: "上海"
},
{
id: nanoid(),
age: 32,
name: '王小美',
address: "深圳"
},
{
id: nanoid(),
age: 22,
name: '王小希',
address: "上海"
},
]
const [defaultAgeRange, setDefaultAgeRange] = useState([])
const [defaultAddresList, setDefaultAddresList] = useState([])
const [tableSources, setTableSources] = useState([])
const navigate = useNavigate()
const [searchParams, setSearchParams] = useSearchParams()
useEffect(() => {
getAgeRange()
getUsersAddress()
}, [searchParams])
const getAgeRange = (max = 100, range = 10) => {
let ageRange = []
for (let i = 0; i < max; i += range) {
const checked = searchParams.get("ageRange")?.length > 0 ? searchParams.get("ageRange").includes(`${i}-${i + range}`) : undefined
ageRange.push({
id: nanoid(),
label: `${i}-${i + range}`,
value: {
min: i,
max: i + range
},
checked,
})
}
setDefaultAgeRange(ageRange)
}
const getUsersAddress = () => {
if (users?.length > 0) {
const addresList = users?.map((item) => item?.address)
const uniqueAddresList = [...new Set(addresList)].map((item) => {
const checked = searchParams.get("addresList")?.length > 0 ? searchParams.get("addresList").includes(item) : undefined
return {
id: nanoid(),
label: item,
value: item,
checked,
}
})
setDefaultAddresList(uniqueAddresList)
}
}
const changeChecked = (checked, value, fn) => {
fn((pre) => {
return pre.map((item) => {
if (item.value === value) {
return {
...item,
checked,
}
} else {
return item
}
})
})
}
const onSumbit = (settUrl = true) => {
const ageRange = defaultAgeRange.filter((item) => item.checked)
const addresList = defaultAddresList.filter((item) => item.checked).map((item) => item.value)
if (ageRange.length == 0 && addresList.length == 0) {
alert("请选择筛选条件")
}
let finde = []
let url = ""
if (ageRange.length > 0) {
users.filter((item) => {
ageRange.forEach((ite) => {
if (ite.value.min <= item.age && ite.value.max > item.age) {
finde.push(item)
}
})
})
const ageRangeValue = ageRange.map((item) => item.label)
url = `ageRange=${ageRangeValue}`
}
if (addresList.length > 0) {
finde = url.length > 1 ? finde.filter((item) => addresList.includes(item.address)) : users.filter((item) => addresList.includes(item.address))
url = url.length > 1 ? `${url}&addresList=${addresList.join(',')}` : `addresList=${addresList.join(',')}`
}
console.log(" finde==>", finde)
setTableSources(finde)
if (settUrl) {
navigate(`/shoppingMall?${url}`)
}
}
const clearAll = (data, fu) => {
const newData = data.map((item) => {
return {
...item,
checked: false
}
})
fu([...newData])
}
const onReset = () => {
clearAll(defaultAgeRange, setDefaultAgeRange)
clearAll(defaultAddresList, setDefaultAddresList)
}
const combineCompoent = (title, defaultList, changeFun) => {
return <Fragment>
<h2>{title}:
{
defaultList?.filter((item) => item.checked)?.map((item, index) => {
return <Fragment>
<span style={{ marginRight: "10px" }} key={`select${index}`}>{item.label}</span>
</Fragment>
})
}
{defaultList?.some((item) => item?.checked) && <a key={`clear${title}`} style={{ color: "red" }} onClick={() => clearAll(defaultList, changeFun)}>清空</a>
}
</h2>
<div>
{
defaultList?.map((item, index) => {
return <Fragment>
<div style={{ display: "inline-block", width: "75px",border: "1px solid #ccc", borderRadius: "5px",marginLeft: "10px"}} key={`default${index}`}>
<input type='checkbox'
onChange={(e) => changeChecked(e.target.checked, item.value, changeFun)} checked={item?.checked} />{item.label}
</div>
</Fragment>
})
}
<hr />
</div>
</Fragment>
}
return (
<div>
<div key={"ageList"}>
{combineCompoent("年龄", defaultAgeRange, setDefaultAgeRange)}
</div>
<div key={"cityList"}>
{combineCompoent("城市", defaultAddresList, setDefaultAddresList)}
</div>
<div style={{
display: "flex",
justifyContent: "flex-end",
}}>
<button style={{ marginRight: "10px" }} onClick={() => onReset()}>取消</button>
<button style={{ color: "red" }} onClick={() => onSumbit()}>提交</button>
</div>
<br />
<table >
<thead>
<tr>
<th > ID </th>
<th >Name</th>
<th >Age</th>
<th >City</th>
</tr>
</thead>
<tbody>
{
tableSources.length > 0 ? tableSources?.map((item) => {
return <tr style={{ textAlign: "center" }} key={item?.id}>
<td >{item?.id}</td>
<td >{item?.name}</td>
<td >{item?.age}</td>
<td >{item?.address}</td>
</tr>
}) : <tr style={{ textAlign: "center" }}>
<td >暂无数据</td>
<td >暂无数据</td>
<td >暂无数据</td>
<td >暂无数据</td>
</tr>
}
</tbody>
</table>
</div>
)
}
样式:
/* 基础表格样式 */
table {
border-collapse: collapse;
/* 关键:合并边框 */
width: 100%;
font-family: Arial, sans-serif;
}
/* 设置所有单元格边框 */
th,
td {
border: 2px solid #7adb59;
/* 1px实线边框,颜色自定义 */
padding: 8px;
text-align: left;
background-color: #c9edd8;
}
/* 表头样式 */
th {
background-color: #c9edd8;
border-color: #7adb59;
/* 表头边框颜色可不同 */
}
小结
实现代码中,我创建了mock data。只有简单的四条而已哈;如果想看更多数据的搜寻,可以自己再多创建几条数据;
使用到hook有 useEffect, useState,useNavigate, useSearchParams;
nanoid() 是可以生成随机唯一的id的
useNavigate 是可以跳转路由的
useSearchParams 是可以获取路由的参数的