前言: 上篇文章是使用 antd@4 table 自定义表头筛选完成一个表格动态列的功能,这次需要完成一个表头联动条件筛选功能。
一、开始前
开始之前先去 Antd 官网看下「自定义的列筛选功能」的代码和逻辑:
插一句:
目前我做的是 PC 后台管理系统,系统里面涉及到大量带条件筛选的表头,项目中「table 自定义列筛选功能」这个组件是另一个小伙伴封装的,封装的还可以,就是没用到 Antd 「自定义的列筛选功能」提供的 API ,导致后面有很多效果需要自己去手动实现,例如: 筛选图标点亮、搜索框输入查询条件不点击确认自动清空效果等,因为项目比较急,没办法我只能全手动加上,结果造成代码非常的臃肿。
二、模拟大量数据
项目中的接口肯定是不能直接拿来做 demo 演示的,而且就算我拿来了,大家也连不了,都是内网,还是老老实实的模拟接口吧。
模拟数据使用的模块 json-server 和 mockjs ,详细使用参考我去年写的文章:学习使用 json-server 和 mockjs
看看我去年写的代码,想想过的真快,都一年整了,哎!那时候好连 ES6 都不是太会 ,感觉进步好大,用写博客逼着自己成长,各位观众没事也来试试呗。
好了,看下本次模拟数据的逻辑代码和注释:
// 使用 Mock
const Mock = require('mockjs');
const pinyin = require("pinyin");
// 引入node内置的文件系统
const { writeFile } = require('fs');
// 使用Random这个api
const random = Mock.Random;
// 统计 national 、province、education、作为查询条件
let nationalArr = [], provinceArr = [], educationArr = [];
// 汉字转拼音
function han2pinyin(han) {
return [].concat(...pinyin(han, {
// 拼音不加音调
style: pinyin.STYLE_NORMAL
})).join("");
};
const tableData = [];
for (let i = 0;i < 100;i++) {
// 随机56个民族
const national = random.pick(["汉族","蒙古族","回族","藏族","维吾尔族","苗族","彝族","壮族","布依族","朝鲜族","满族","侗族","瑶族","白族","土家族","哈尼族","哈萨克族","傣族","黎族","僳僳族","佤族","畲族","高山族","拉祜族","水族","东乡族","纳西族","景颇族","柯尔克孜族","土族","达斡尔族","仫佬族","羌族","布朗族","撒拉族","毛南族","仡佬族","锡伯族","阿昌族","普米族","塔吉克族","怒族","乌孜别克族","俄罗斯族","鄂温克族","德昂族","保安族","裕固族","京族","塔塔尔族","独龙族","鄂伦春族","赫哲族","门巴族","珞巴族","基诺族"]);
!nationalArr.includes(national) && nationalArr.push(national);
// 随机省份
let province;
do {
province = random.province();
} while(province === "山西省");
!provinceArr.includes(province) && provinceArr.push(province);
// 随机出受教育程度
const education = random.pick(["初中","高中","大专","本科","研究生"]);
!educationArr.includes(education) && educationArr.push(education);
// 数据放入数组arr
tableData.push({
"id" : i,
province,
education,
national
});
};
nationalArr = nationalArr.map(national => ({ title: national, value: han2pinyin(national)}));
provinceArr = provinceArr.map(province => ({ title: province, value: han2pinyin(province)})); /* 注意哦:陕西省和山西省的拼音一样的 */
educationArr = educationArr.map(education => ({ title: education, value: han2pinyin(education)}));
const db = { tableData, nationalArr, provinceArr, educationArr };
// 文件写入
writeFile("./db.json",JSON.stringify(db),function(err){
if (err) {
console.log(`写入错误,错误为:${err}`);
return ;
};
console.log("一百条信息录入成功!");
});
我通过 npx json-server --watch db.json --port 3000 来启动接口,一共启用四个接口链接分别为:
http://localhost:3000/tableData
http://localhost:3000/nationalArr
http://localhost:3000/provinceArr
http://localhost:3000/educationArr
浏览器打开即可看到数据。
为了证明俺没骗你,截图为证
三、table 用到的一些样式
写 CSS 也是挺费劲的,做人不能不厚道,样式也送给大家,注:是 less 文件。
/*多选框去掉三角和文字*/
.ant-select-tree {
padding-left: 12px !important;
span.ant-select-tree-switcher,
.ant-select-tree-indent {
display: none;
}
}
.table-filter-dropdown {
position: relative;
padding: 6px;
box-shadow: 0px 2px 8px 0px rgba(0, 0, 0, 0.15);
.tree-select {
width: 150px;
margin-right: 5px;
vertical-align: middle;
.ant-select-selector {
height: 26px;
.ant-select-selection-item {
display: none;
}
}
}
.ant-btn {
height: 26px;
width: 70px;
vertical-align: middle;
}
.common-remove-filter {
position: absolute;
right: 86px;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
color: #C2C2C2;
}
.common-treeSelect-dropdown {
top: 32px !important;
left: -6px !important;
border-top: 1px solid #E8E8E8;
}
}
四、数据渲染到表格
开始写代码之前我们确保知道 filterDropdown 函数四个形参的作用,不会回到标题一去看 Antd 官网:
setSelectedKeys 设置值
selectedKeys 存储值
confirm ok 时触发,清除搜索框输入的值和关闭筛选模块
clearFilters cancel 时触发,清除搜索框输入的值和关闭筛选模块
前端表头筛选
前端控制的表头筛选
对应的源代码和注释:
import React from 'react';
import 'antd/dist/antd.css';
import { Table, Button, Space, TreeSelect } from 'antd';
import { FilterOutlined } from '@ant-design/icons';
import Axios from 'axios';
import "./filterItem.less";
const SHOW_PARENT = TreeSelect.SHOW_PARENT;
export default class App extends React.Component {
state = {
// table 的 dataSource
dataSource: [],
// 表头三个下拉列表
educationArr: [],
nationalArr: [],
provinceArr: []
};
// 请求数据
async componentDidMount() {
const { data: tableData } = await Axios.get("http://localhost:3000/tableData");
const { data: provinceArr } = await Axios.get("http://localhost:3000/provinceArr");
const { data: nationalArr } = await Axios.get("http://localhost:3000/nationalArr");
const { data: educationArr } = await Axios.get("http://localhost:3000/educationArr");
this.setState({
dataSource: tableData,
educationArr,
nationalArr,
provinceArr
});
}
// treeSelect 组件 => 使用 treeData 把 JSON 数据生成树结构。
itemSelection = (treeData, dataIndex, selectedKeys, setSelectedKeys) => {
// 这些配置去 https://ant.design/components/tree-select-cn/ 查看
const tProps = {
treeData,
value: selectedKeys,
defaultValue: [],
placeholder: `Select ${dataIndex}`,
autoClearSearchValue: false,
treeCheckable: true,
maxTagCount: 0,
treeNodeFilterProp: 'title',
treeDefaultExpandAll: true,
showCheckedStrategy: SHOW_PARENT,
getPopupContainer: (triggerNode) => triggerNode.parentNode,
size: 'small',
className: 'tree-select',
dropdownMatchSelectWidth: 217,
dropdownClassName: 'common-treeSelect-dropdown'
};
tProps.onChange = value => {
setSelectedKeys(value);
};
return ;
}
// 格式化数据为 treeSelect 组件所需要的格式