react自定义汇总行并固定在底部

react自定义汇总行并固定在底部

安装依赖
react 这个不用说了吧
antd UI组件库
Mockjs 造数据
react-highlight-words 查询结果高亮
@ant-design/icons 图标

视频预览

react自定义汇总行并固定在底部_第1张图片
react自定义汇总行并固定在底部_第2张图片
react自定义汇总行并固定在底部_第3张图片

/**
 * Created by lidianzhong on 2020-07-08.
 * E-mail: [email protected].
 * To: More pain, more gain.
 */

import React, {useState} from 'react';
import {Table, Pagination,Select, Checkbox,Input, Button, Space} from 'antd';
import {PlusCircleTwoTone,SearchOutlined, MinusCircleTwoTone} from '@ant-design/icons';
import Highlighter from 'react-highlight-words';
import styles from './style.less';
import Mock from "mockjs";

const {Option} = Select;
const dataSource = Array(100)
  .fill(0, 0, 100)
  .map((item, i) => {
    return Mock.mock({
      index: i + 1,
      key: i + 1,
      "name|1": ['胡彦斌', "kankan", "kankan1"],
      "money|1-100": 32,
      address: Mock.mock("@city()"),
      address0: Mock.mock("@city()"),
      address1: Mock.mock("@city()"),
      address2: Mock.mock("@city()"),
      address3: Mock.mock("@city()"),
      address4: Mock.mock("@city()"),
      address5: Mock.mock("@city()"),
      address6: Mock.mock("@city()"),
    })
  });

const defaultPageSize = 20;
const TableComponents = () => {

  const [filteredInfo, setFilteredInfo] = useState({});
  const [sortedInfo, setSortedInfo] = useState({});
  const [data, setData] = useState([]);
  const [selectedRowKeys, setSelectedRowKeys] = useState([1,2,3]);
  const [searchText, setSearchText] = useState('');
  const [searchedColumn, setSearchedColumn] = useState('');

  useState(() => {
    queryFun(1, defaultPageSize);
  }, [])

  const children1=[];
  for (let i = 0; i < 7; i++) {
    children1.push({
      title: '住址' + i, dataIndex: 'address' + i, key: 'address' + i, width: 200,
      ...getColumnSearchProps('address' + i),
    });
  }
  let columns = [
    {
      title: "序号",
      dataIndex: 'index',
      key: 'index',
      width: 100,
      fixed: 'left',
    },
    {
      title: <span>姓名<Checkbox/></span>,
      dataIndex: 'name',
      key: 'name',
      width: 100,
      align: 'center',
      ellipsis: true,
      className: 'kankan',
      // colSpan:1,
      // defaultFilteredValue:'kankan',
      // defaultSortOrder:'ascend',
      // filterDropdownVisible:true,
      // filtered:true,
      filterMultiple: true,
      // filterDropdown:()=>
filterDropdown
,
onCell: (record, rowIndex) => { return { onClick: event => { // console.log("onCell单击行触发") }, // 点击行 onDoubleClick: event => { // console.log("onCell双击行触发") }, onContextMenu: event => { // console.log("onCell菜单触发") }, onMouseEnter: event => { // console.log("onCell鼠标移入触发") }, // 鼠标移入行 onMouseLeave: event => { // console.log("onCell鼠标移出触发") }, }; }, // onFilter:(e)=>{}, // onFilterDropdownVisibleChange:()=>{}, onHeaderCell: column => { return { onClick: event => { // console.log("onHeaderCell单击行触发") }, // 点击行 onDoubleClick: event => { // console.log("onHeaderCell双击行触发") }, onContextMenu: event => { // console.log("onHeaderCell菜单触发") }, onMouseEnter: event => { // console.log("onHeaderCell鼠标移入触发") }, // 鼠标移入行 onMouseLeave: event => { // console.log("onHeaderCell鼠标移出触发") }, }; }, filters: [ {text: 'kankan', value: 'kankan'}, {text: 'kankan1', value: 'kankan1'}, {text: '胡彦斌', value: '胡彦斌'}, ], filteredValue: filteredInfo.name || null, onFilter: (value, record) => record.name.includes(value), }, { title: '身价', dataIndex: 'money', key: 'money', width: 100, defaultSortOrder: 'ascend', sortDirections: ["ascend", "descend"], showSorterTooltip: true, sorter: (a, b) => a.money - b.money, sortOrder: sortedInfo.columnKey === 'money' && sortedInfo.order, }, { title: '住址', children: [ {title: '住址', dataIndex: 'address', key: 'address', width: 200, ...getColumnSearchProps("address") }, ...children1, ] }, ]; /** * @fun self-define summery. * @param currentData * @returns {*} */ const onSummary = (currentData) => { const a = { index: '总计', key:"total", name: '', money: 0, address: '', address0: "", address1: "", address2: "", address3: "", address4: "", address5: "", address6: "", }; const data = currentData.reduce((total, currentValue, currentIndex, arr) => { return { ...a, money: total.money + currentValue.money, } }, a) return <> <Table.Summary.Row> <Table.Summary.Cell key={0} index={0}/> <Table.Summary.Cell key={1} index={1}/> {columns .reduce((total,curr,index,arr)=> curr.children ? total.concat(curr.children) : total.concat(curr),[]) .map((i, j) => <Table.Summary.Cell key={j+2} index={j+2}> {data[i.dataIndex]} </Table.Summary.Cell> ) } </Table.Summary.Row> </> } /** * @expandable params. * @type {{expandIconColumnIndex: number, expandRowByClick: boolean, onExpand: onExpand, expandIcon: (function({expanded: *, onExpand: *, record?: *}): *), onExpandedRowsChange: onExpandedRowsChange, childrenColumnName: string, defaultExpandAllRows: boolean, expandedRowRender: (function(*, *, *, *): *), rowExpandable: (function(*): boolean), indentSize: number}} */ const expandableSelect = { rowExpandable: record => record.name !== 'kankan1', childrenColumnName: '展开', defaultExpandAllRows: false, // defaultExpandedRowKeys: [1], expandIcon: ({expanded, onExpand, record}) => { //https://codesandbox.io/s/fervent-bird-nuzpr?file=/index.js:1450-1677 return expanded ? ( <MinusCircleTwoTone onClick={e => onExpand(record, e)}/> ) : ( <PlusCircleTwoTone onClick={e => onExpand(record, e)}/> ) }, expandIconColumnIndex: 0, // expandedRowKeys: [2,6], expandedRowRender: (record, index, indent, expanded) => { // console.log(record, index, indent, expanded); return <div style={{backgroundColor: 'pink'}}> <p>record:{record.name}</p> <p>index:{index}</p> <p>indent:{indent}</p> <p>expanded:{expanded}</p> </div> }, indentSize: 20, expandRowByClick: true, onExpand: (expanded, record) => { // console.log(expanded, record); }, onExpandedRowsChange: (expandedRows) => { // console.log("expandedRows", expandedRows) } } /** * @fun rowSelect params. * @type {{selections: ["SELECT_ALL", "SELECT_INVERT", {text: string, key: string, onSelect: function(*): void}, {text: string, key: string, onSelect: function(*): void}, {text: string, key: string, onSelect: function(*): void}], onChange: onChange, onSelectAll: onSelectAll, onSelectInvert: onSelectInvert, selectedRowKeys: number[], columnWidth: number, fixed: boolean, checkStrictly: boolean, preserveSelectedRowKeys: boolean, getCheckboxProps: getCheckboxProps, renderCell: (function(*=, *=, *=, *=): *), type: string}} */ const rowSelection={ checkStrictly:true, columnWidth:100, // columnTitle:选择 , fixed:true, getCheckboxProps:(record)=>{ // console.log(record); }, preserveSelectedRowKeys:true, renderCell:(checked, record, index, originNode) =>{ // console.log(checked, record, index, originNode); return <span>{index} {originNode}</span>; }, selectedRowKeys, // selections:true, selections: [ Table.SELECTION_ALL, Table.SELECTION_INVERT, { key: 'odd', text: 'Select Odd Row', onSelect: changableRowKeys => { let newSelectedRowKeys = []; newSelectedRowKeys = changableRowKeys.filter((key, index) => { return index % 2 === 0; }); setSelectedRowKeys(newSelectedRowKeys); }, }, { key: 'even', text: 'Select Even Row', onSelect: changableRowKeys => { let newSelectedRowKeys = []; newSelectedRowKeys = changableRowKeys.filter((key, index) => { return index % 2 !== 0; }); setSelectedRowKeys(newSelectedRowKeys); }, }, { key: 'link', text: '模糊匹配', onSelect: changableRowKeys => { let newSelectedRowKeys = []; newSelectedRowKeys = changableRowKeys.filter((key, index) => { return index % 2 !== 0; }); setSelectedRowKeys(newSelectedRowKeys); }, }, ], type:'checkbox', onChange:(selectedRowKeys, selectedRows)=>{ setSelectedRowKeys(selectedRowKeys); }, onSelectAll:(selected, selectedRows, changeRows)=>{}, onSelectInvert:(selectedRowKeys)=>{} } /** * @fun listen pagination filters sorter changed. * @param pagination * @param filters * @param sorter */ const handleChange = (pagination, filters, sorter) => { // console.log('Various parameters', pagination, filters, sorter); setFilteredInfo(filters); setSortedInfo(sorter); }; /** * @fun search data. * @param page * @param size */ function queryFun(page, size) { setData([...dataSource].splice((page - 1) * size, size)); } /** * @fun self-define filter. * @param dataIndex * @returns {{filterDropdown: (function({setSelectedKeys: *, selectedKeys?: *, confirm?: *, clearFilters?: *}): *), filterIcon: (function(*): *), onFilter: (function(*, *): boolean), onFilterDropdownVisibleChange: onFilterDropdownVisibleChange, render: (function(*): *)}} */ function getColumnSearchProps (dataIndex){ return { filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => { const set= new Set(); dataSource.map(i=>{set.add(i[dataIndex])}) return( <div style={{ padding: 8 }}> <span style={{fontSize:12,padding:4,display:'block',textAlign:'center',color:'#0189ff'}}>根据业务选择不同匹配模式</span> <Input value={selectedKeys[0]} placeholder={"模糊匹配"} onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])} onPressEnter={() => handleSearch(selectedKeys, confirm, dataIndex)} style={{ width: 188, marginBottom: 8, display: 'block' }} /> <Select placeholder={"精确匹配"} value={selectedKeys[0]} onChange={e => setSelectedKeys(e? [e] : [])} onPressEnter={() => handleSearch(selectedKeys, confirm, 'address1')} style={{ width: 188, marginBottom: 8, display: 'block' }} showSearch > {[...set].map((i,j)=> <Option key={j+1} value={i}>{i}</Option>)} </Select> <Space> <Button type="primary" onClick={() => handleSearch(selectedKeys, confirm, dataIndex)} icon={<SearchOutlined />} size="small" style={{ width: 90 }} > 搜索 </Button> <Button onClick={() => handleReset(clearFilters)} size="small" style={{ width: 90 }}> 重置 </Button> </Space> </div> )}, filterIcon: filtered => <SearchOutlined style={{ color: filtered ? '#1890ff' : undefined }} />, // 由于自定义搜索,下面过滤不生效 onFilter: (value, record) =>record[dataIndex].indexOf(value) === 0, onFilterDropdownVisibleChange: visible => { if (visible) { // console.log(searchInput); // searchInput.select() } }, render: text => searchedColumn === dataIndex ? ( <Highlighter highlightStyle={{ backgroundColor: '#ffc069', padding: 0 }} searchWords={[searchText]} autoEscape textToHighlight={text.toString()} /> ) : ( text ), } } /** * * @param selectedKeys * @param confirm * @param dataIndex */ const handleSearch = (selectedKeys, confirm, dataIndex) => { confirm(); setData(dataSource.filter((i,j)=>i[dataIndex].toString().includes(selectedKeys[0])).splice(0, defaultPageSize)); setSearchText(selectedKeys[0]); setSearchedColumn(dataIndex); }; /** * * @param clearFilters */ const handleReset = clearFilters => { clearFilters(); setData([...dataSource].splice(0, defaultPageSize)); setSearchText(''); }; return (<div className={styles['table-box']}> <Table // title={(currentPageData) => titleFunction(currentPageData)} dataSource={data} columns={columns} showHeader={true} bordered={true} summary={(currentData) => onSummary(currentData)} scroll={{x: 800, y: 400}} size={'small'} onChange={(pagination, filters, sorter) => handleChange(pagination, filters, sorter)} // onHeaderRow={(column, index)=> onHeaderRow(column, index)} // onRow={(column, index)=> onRow(column, index)} onRow={(record, index) => { return { onClick: event => { // console.log("单击行触发") }, // 点击行 onDoubleClick: event => { // console.log("双击行触发") }, onContextMenu: event => { // console.log("菜单触发") }, onMouseEnter: event => { // console.log("鼠标移入触发") }, // 鼠标移入行 onMouseLeave: event => { // console.log("鼠标移出触发") }, }; }} onHeaderRow={column => { return { onClick: () => { // console.log("点击表头行触发", column); }, // 点击表头行 }; }} // sortDirections={["ascend","descend"]} // showSorterTooltip={true} expandable={expandableSelect} rowSelection={rowSelection} pagination={false} /> <Pagination style={{float: 'right'}} onChange={(page, pageSize) => { queryFun(page, pageSize); }} onShowSizeChange={(current, size) => { queryFun(current, size); }} total={dataSource.length} showSizeChanger showQuickJumper pageSizeOptions={[10, 20, 50, 100, 200]} defaultCurrent={1} defaultPageSize={defaultPageSize} showTotal={total => `总计 ${total} 条`} /> </div>) } export default TableComponents;
// 自定义样式和组件样式覆盖
.table-box :global {
  padding: 50px;
  // https://www.runoob.com/css/css-positioning.html#position-sticky
  .ant-table-body {
    tfoot > tr > td {
      position: sticky;
      border-top: 1px solid #eee;
      background-color: #1fc695;
      bottom: 0;
    }
  }
}


你可能感兴趣的:(antd,React,CSS)