• React Table 表格 的合并单元格、隔行变色的技巧(转载)


    前言:基础的用法就不强调了,这里一笔带过。接下来直接看代码。注意:关键代码用红色粗体字体

    第一个例子:合并单元格

      在这个例子里,根据antd官网介绍,可以看到这样一句话:表头只支持列合并,使用 column 里的 colSpan 进行设置。表格支持行/列合并,使用 render 里的单元格属性 colSpan 或者 rowSpan设值为 0 时,设置的表格不会渲染。转换一下,让我们一开始就在数据中埋下一个 span 属性,方便后续操作。

    复制代码
    import React, { useState, useEffect,useCallback } from 'react';
    import './index.less';
    import { Modal, Table } from 'antd'; 
    import moment from 'moment';
    import { config_discount_list } from '../../../services/api'; 
    
    function DiscountsDetailModal(props) {
      const [tableData, setTableData] = useState([]);               // list数据
      const [visible,setVisible ] = useState(false);
      const [tableColumns,setTableColumns] = useState([]);
      const [filterParams, setFilterParams] = useState({});  // 查询表单的参数
      // const [updateList, setUpdateList] = useState([]); // 回显
      const [serveConfigId, setServeConfigId] = useState();  // 是否修改状态 
      // const format = 'HH:mm';
      // const dateFormat = 'YYYY/MM/DD';
    
      // 后端返回的数据
      // [
      //   {
      //     dateDiscount: 1,
      //     endDate: "2019-01-02",
      //     startDate: "2019-01-01",
      //     timeData:[
      //       {
      //         discountPrice: 1,
      //         endTime: "21:21:21",
      //         startTime: "20:20:20",
      //         timeDiscount: 1,
      //       },
      //       {
      //         discountPrice: 2,
      //         endTime: "21:21:21",
      //         startTime: "20:20:20",
      //         timeDiscount: 2,
      //       },
      //       {
      //         discountPrice: 3,
      //         endTime: "21:21:21",
      //         startTime: "20:20:20",
      //         timeDiscount: 3,
      //       }
      //     ]
      //   },
      //   {
      //     dateDiscount: 1,
      //     endDate: "1111-11-11",
      //     startDate: "1111-11-11",
      //     timeData:[
      //       {
      //         discountPrice: 0.012,
      //         endTime: "00:00:00",
      //         startTime: "00:00:00",
      //         timeDiscount: 2,
      //       },
      //       {
      //         discountPrice: 0.013,
      //         endTime: "00:00:00",
      //         startTime: "00:00:00",
      //         timeDiscount: 3,
      //       }
      //     ]
      //   }
      // ]
    
      // 我操作以后得出的数据
      //  [
      //     {
      //       key:0,
      //       date:'1111',
      //       dateDiscount:'0.1',
      //       createTime:'1111-22222',
      //       timeDiscount:'0.222',
      //       discountPrice:'1111',
      //       span:2, // :0 代表不占行 :1 代表占一行,:2 代表占两行,以此类推,
    // 当这里占了两行,下一行一定要为空行,即 span:0
    // 同理这里是 :3 的话,下面必须连续出现两个 span:0
    // }, // { // key:1, // date:'222', // dateDiscount:'0.1', // createTime:'55555-66666', // timeDiscount:'0.3333', // discountPrice:'2222', // span:0, // }, // { // key:2, // date:'3333', // dateDiscount:'0.1', // createTime:'77777-88888', // timeDiscount:'0.4444', // discountPrice:'3333', // span:4, // }, // { // key:3, // date:'444444', // dateDiscount:'0.1', // createTime:'77777-88888', // timeDiscount:'0.4444', // discountPrice:'3333', // span:0, // }, // { // key:4, // date:'55555', // dateDiscount:'0.1', // createTime:'77777-88888', // timeDiscount:'0.4444', // discountPrice:'3333', // span:0, // }, // { // key:5, // date:'66666', // dateDiscount:'0.1', // createTime:'77777-88888', // timeDiscount:'0.4444', // discountPrice:'3333', // span:0, // } // ] const requestList = useCallback(async () => { let res = await config_discount_list({ serveConfigId}); if (res.data.responseCode) return let responseData = res.data.responseData; setVisible(true) let arr = []; responseData.map(responseDataItem=>{ const len = responseDataItem.timeData.length; responseDataItem.timeData.map((timeDataItem,index)=>{ arr = [ ...arr, { time:timeDataItem.startTime+'-'+timeDataItem.endTime, discountPrice: timeDataItem.discountPrice, timeDiscount: timeDataItem.timeDiscount, date:responseDataItem.startDate === '1111-11-11' ? '其他日期' : responseDataItem.startDate+'-'+responseDataItem.endDate, dateDiscount:responseDataItem.dateDiscount, span:index === 0 ? len : 0 } ] return arr }) return arr }) const tableData = arr.map((item, index) => { item.key = index; return item; }) setTableData(tableData); }) useEffect(()=>{ setVisible(props.visible); setServeConfigId(props.serveConfigId); }, [props.visible, props.serveConfigId]) useEffect(()=>{ if(serveConfigId && serveConfigId !== -1){ requestList() } }, [serveConfigId]) useEffect(()=>{ setTableColumns([ { title: '日期', dataIndex: 'date', key: 'date', 140, render: (value, row, index) => { // 需要被合并的单元格,只需要这样设置就行了。比官网的简单,但是,一开始要处理好数据中的 span 属性。 return {// 这里可以返回标签,比如:return <span title={value}>{value}</span> children: value, props: {rowSpan:row.span}, }; }, }, { title: '日期折扣', dataIndex: 'dateDiscount', key: 'dateDiscount', 140, render: (value, row) => { return { children: value, props: {rowSpan:row.span}, }; }, }, { title: '时间', dataIndex: 'createTime', key: 'createTime', 140 }, { title: '时间折扣', dataIndex: 'timeDiscount', key: 'timeDiscount', 140 }, { title: '价格(元)', dataIndex: 'discountPrice', key: 'discountPrice', 140 } ]) }, []) const onCancel = () => { setVisible(false) props.close(false) } return ( <Modal destroyOnClose={true} className="discountsDetailModal" title="优惠详情" centered visible={ visible } onCancel={ onCancel } okText="确定" cancelText="取消" maskClosable={ false } width={600} > <Table columns={tableColumns} dataSource={tableData} bordered /> </Modal> ) } export default DiscountsDetailModal;
    复制代码

    到此为止,我们完成了表格的合并列,新的问题是如果需要隔行变色显示,这是可以发现隔行变色并不是我们想要的样式。

    下面有请第二个例子:隔行变色

      rowClassName这一api,通过判断index的奇偶来实现不同的样式分配。 rowClassName是一个函数,它的第一个参数是record,对应的是这一行的所有数据,第二个参数是index,对应的是table组件自己计数的第几行;

    没有合并单元格的简单情况:

      直接判断index的奇偶作出不同的样式分配;然后根据不同的 className 进行隔行变色的 css 修改

    rowClassName={(record, index) => {
      let className = 'odd';
      if (index % 2 === 1) className = 'even';
      return className;
    }}

    合并单元格后的复杂情况:

      如果依靠rowClassName中自带的index是不行的,所以这时候需要自己设定一个fakeIndex和一个用来指示此行是否被合并的标志(我设的是一个标志从此行起还有多少合并行的计数count,遇到普通行,fakeIndex加1;如果遇到被合并的行,则fakeIndex不加1,count减1。这里可以这么做的原因是antd的表格在渲染的时候是每渲染一行,就执行一次rowClassName的函数。
    具体实现代码如下:
    首先在React Component的constructor里面申明fakeIndexcount

    constructor() {
      super();
      this.fakeIndex = 0;
      this.licensesCount = 1;
    }

    然后在render渲染的<Table/>里面设置rowClassName函数

    复制代码
    <Table
      columns={tableColumns}
      dataSource={tableData}
      bordered  // 是否展示外边框和列边框
      className="reset-ant-table"
      pagination={false} // 分页器,参考配置项或 pagination 文档,设为 false 时不展示和进行分页
      scroll={{y: 300}} //表格是否可滚动,配置项
      rowClassName = {
        record => {
          let className = 'reset-ant-table odd';
          if (record.span > 1) {
            this.licensesCount = record.span; // 用来初始化合并的行数
          }
          if (record.span !== 0) {
            className = "reset-ant-table odd oddHover";
            if (this.fakeIndex % 2 === 1) {
              className = 'reset-ant-table even evenHover';
            }
          } else {
            if (this.fakeIndex % 2 === 1) {
              className = 'reset-ant-table even';
            }
          }
          if (record.span === 0) {
            this.licensesCount--
            if (this.licensesCount === 1) {
              this.fakeIndex++
            }
          }
          if (record.span === 1) {
            this.fakeIndex++
          }
          return className;
        }
      }
    ></Table>
    复制代码

    className 中的 odd 和 even 可以设置隔行变色,oddHover 和 evenHover 可以设置鼠标移上时的样式,虽然不能说完美,单至少是一种解决方案。

    那么顺便把 less 也加上,可供参考:

    复制代码
    .reset-ant-table{
      .ant-table-tbody{
        tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected) > td {
          background-color: #DFE8FF;
        }
        .oddHover:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected) > td:first-child{
          background-color: #FFFFFF;
        }
        .evenHover:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected) > td:first-child{
          background-color: #F0F4FD;
        }
        .odd{
          background-color: #FFFFFF;
        }
        .even{
          background-color: #F0F4FD;
        }
      }
    }
    复制代码

    其它一些用过的 API 的例子

      当你在官网查找 api ,却还是不明白如何使用,这里让你剪切复制就好,ps:有栗子就是好

    1. 默认文案设置

    <Table
     emptyText={"暂无数据"}
     filterConfirm={"确定"}
     filterReset= {"重置"}
    ></Table>

    2. 表格行 key 的取值,可以是字符串或一个函数

    <Table
      rowKay={(recode, index) => `${recode.id}${index}`}
    ></Table>

    3. onRow 的用法

      没错,就是官网上抄的,此例子适用于 onRowonHeaderRowonCellonHeaderCell

    复制代码
    <Table
      onRow={record => {
        return {
          onClick: event => {}, // 点击行
          onDoubleClick: (event, val) => {}, // 如果第一个参数不能满足你,可以看看第二个
          onContextMenu: event => {},
          onMouseEnter: event => {},
          onMouseLeave: event => {},
        };
      }}
      onHeaderRow={column => {
        return {
          onClick: () => {}, // 点击表头行
        };
      }}
    />
    复制代码
  • 相关阅读:
    结对项目刘畅2016012040
    Daily target小队介绍(刘畅,陈杰,杨有存,唐祎琳,王晓哲,邵汝佳)
    第四、十七章读书报告
    2016012040+小学四则运算练习软件项目报告
    JAVA之路(二)
    使用pip命令可能遇到的报错
    monkey命令
    Mitmproxy 手机配置代理
    appium安装与简单使用
    自动化测试第十一节---unittest
  • 原文地址:https://www.cnblogs.com/snowhite/p/12580660.html
Copyright © 2020-2023  润新知