封装组件是为了能在开发过程中高度复用功能和样式相似的组件,以便我们只关注于业务逻辑层的处理,提高开发效率,提高逼格,降低代码重复率,降低劳动时间,减少加班的可能。

本次组件的封装采用了函数式组件即无状态组件的方式来提高页面渲染性能,由于无状态组件在数据变更后不会主动触发页面的重新渲染,所以本次的封装也用到了React Hooks。下面简要介绍一下函数式组件和React Hooks。

函数式组件是被精简成一个render方法的函数来实现的,由于是无状态组件,所以无状态组件就不会再有组件实例化的过程,无实例化过程也就不需要分配多余的内存,从而性能得到一定的提升。但函数式组件是没有this和ref的,如果强行给函数式组件添加ref会报一个Function components cannot be given refs的错误。函数式组件也没有生命周期,没有所谓的componentWillMount、componentDidMount、componentWillReceiveProps、shouldComponentUpdate等方法。

React Hooks是react16.8引入的特性,他允许你在不写class的情况下操作state和react的其他特性。Hook就是JavaScript函数,但是使用它们会有两个额外的规则:

  • 只能在函数最外层调用Hook,不能在循环、条件判断或者子函数中调用;

  • 只能在React的函数组件中调用Hook,不能在其他JavaScript函数中调用(自定义Hook除外)。

React Hooks中用的比较频繁的方法:

  • useState

  • useEffect

  • useContext

  • useReducer

  • useMemo

  • useRef

  • useImperativeHandle

由于以上方法的具体介绍及使用的篇幅过大,故请自行查阅API或资料,这里不再展开描述。

另外,本次封装一部分采用了JSX来创建虚拟dom节点,一部分采用了createElement方法来创建虚拟dom节点,createElement方法接收三个参数:

第一个参数:必填,可以是一个html标签名称字符串如span、div、p等,也可以是一个react组件;

第二个参数:选填,是创建的标签或组件的属性,用对象方式表示;

第三个参数:选填,是创建的标签或组件的子节点,可以是一个字符串或一个组件,也可以是一个包含了字符串或组件的数组,还可以是一个采用createElement创建的虚拟dom节点。

createElement方法可能用的人不会很多,因为现在有了类似于html的JavaScript语法糖JSX,使用和理解起来也较为直观和方便,符合我们对html结构的认知,但其实JSX被babel编译后的呈现方式就是使用createElement方法创建的虚拟dom,至于为何使用createElement方法,私心觉得可以提升编译打包效率。另外本次封装组件时有些地方也使用了JSX,是觉得在那些地方使用JSX更舒服,而有些地方使用createElement方法私心也觉得更符合js的编写习惯,如果你觉得在一个组件中既有JSX又有createElement会很乱的话,你可以统一使用一种即可。

本次封装所使用到的方法的介绍基本完毕,以下是组件封装的具体实现部分。

先贴一张最后实现的效果图:



1、所封装的antd table组件table.js

import React, { createElement, useState, useImperativeHandle } from 'react'
import PropTypes from 'prop-types'
import { Link } from "react-router-dom"
import { Table } from 'antd';
import { timestampToTime, currency } from '@/utils' const h = createElement;
const TableComp = ({columns, dataSource, hasCheck, cRef, getCheckboxProps}) => {
const empty = '-',
[selectedRowKeys, setSelectedRowKeys ] = useState([]),
[selectedRows, setSelectedRows] = useState([]),
render = {
Default: v => {
if(!v) return empty
return v
},
Enum: (v, row, {Enum}) => {
if(!v || !Enum[v]) return empty
return Enum[v]
},
Loop: v => {
if(v.length < 1) return empty
return v.map((t, idx) => <span key={idx} style={{marginRight: '5px'}}>{t.total}</span>);
},
Action: (v, row, {action}) => {
let result = action.filter(n => {
let {filter = () => true} = n
return filter(row)
}) return result.map(c => <span className="table-link" onClick={() => c.click(row)} key={c.label}>{c.label}</span>)
},
Currency: v => {
if(!v) return empty
return currency(v)
},
Date: v => {
if(!v) return empty
return timestampToTime(v, 'second')
},
Link: (v, row, {url}) => {
if(!v) return empty
return <Link to={url}>{v}</Link>
}
} columns = columns.map(n => {
let { type = 'Default', title, dataIndex, key } = n;
return {title, dataIndex, key, render: (v, row) => render[type](v, row, n) }
}) //父组件获取selectedRowKeys的方法-cRef就是父组件传过来的ref
useImperativeHandle(cRef, () => ({
//getSelectedRowKeys就是暴露给父组件的方法
getSelectedRowKeys: () => selectedRowKeys,
getSelectedRows: () => selectedRows
})); const onSelectChange = (selectedRowKeys, selectedRows) => {
setSelectedRowKeys(selectedRowKeys);
setSelectedRows(selectedRows);
} const rowSelection = {
selectedRowKeys,
onChange: onSelectChange,
getCheckboxProps: record => getCheckboxProps(record)
}; if(hasCheck) return h(Table, {columns, dataSource, rowSelection})
return h(Table, {columns, dataSource})
} TableComp.propTypes = {
columns: PropTypes.array.isRequired, //表格头部
dataSource: PropTypes.array.isRequired, //表格数据
hasCheck: PropTypes.bool, //表格行是否可选择
cRef: PropTypes.object, //父组件传过来的获取组件实例对象或者是DOM对象
getCheckboxProps: PropTypes.func, //选择框的默认属性配置
} export default TableComp

时间戳格式化timestampToTime.js

export const timestampToTime = (timestamp, type) => {
let date = new Date(timestamp); //时间戳为10位需*1000,时间戳为13位的话不需乘1000
let Y = date.getFullYear() + '-';
let M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
let D = date.getDate() < 10 ? '0' + date.getDate() + ' ' : date.getDate() + '';
let h = date.getHours() < 10 ? '0' + date.getHours() + ':' : date.getHours() + ':';
let m = date.getMinutes() < 10 ? '0' + date.getMinutes() + ':' : date.getMinutes() + ':';
let s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds(); if (type == 'second') {
return Y + M + D + ' ' + h + m + s;
} else {
return Y + M + D
}
}

金额千分位currency.js

export const currency = v => {
let [n, d = []] = v.toString().split('.');
return [n.replace(/(\d)(?=(?:\d{3})+$)/g, '$1,')].concat(d).join('.');
};

简单介绍下封装的table组件,本组件基本涵盖了大多数情况下我们所用到的表格组件的情况,包括:操作按钮的权限控制、某一列的跳转、某一列的字段映射以及金额千分位、时间戳格式化和某一列数组数据的循环展示、表格是否可选择等等。如还有其他需求,可自行添加即可。

使用方法:

import React, { useRef } from 'react'
import { Button } from 'antd'
import Table from './components' const TableDemo = () => {
const permission = ["handle", "pass", "refuse", "reApply", 'export'], Enum = {
CREATED: '代办理',
PASS: '待审批',
REJECT: '驳回',
REFUSE: '拒绝',
}; const columns = [
{ title: '姓名', dataIndex: 'name', key: 'name', type: 'Link', url: 'https://www.baidu.com' },
{ title: '年龄', dataIndex: 'age', key: 'age' },
{ title: '状态', dataIndex: 'status', key: 'status', type: 'Enum', Enum, },
{ title: '预警统计', dataIndex: 'statistic', key: 'statistic', type: 'Loop'},
{ title: '存款', dataIndex: 'money', key: 'money', type: 'Currency' },
{ title: '日期', dataIndex: 'date', key: 'date', type: 'Date'},
{ title: '操作', dataIndex: 'action', key: 'action', type: 'Action', action: [
{label: "查看", click: data => {console.log(data)}},
{label: "办理", click: data => {}, filter: ({status}) => status == 'CREATED' && permission.some(n => n == 'handle')},
{label: "通过", click: data => {}, filter: ({status}) => status == 'PASS' && permission.some(n => n == 'pass')},
{label: "驳回", click: data => {}, filter: ({status}) => status == 'REJECT' && permission.some(n => n == 'reject')},
{label: "拒绝", click: data => {}, filter: ({status}) => status == 'CREATED' && permission.some(n => n == 'refuse')},
{label: "重新付款", click: data => {}, filter: ({status}) => status == 'REAPPLY' && permission.some(n => n == 'reApply')},
]},
] const dataSource = [
{key: 1, name: '小坏', age: 20, status: 'CREATED', date: 1596791666000, statistic: [{level: 3, total: 5}, {level: 2, total: 7}, {level: 1, total: 20}, {level: 0, total: 0}], money: 200000000000},
{key: 2, name: 'tnnyang', age: 18, status: 'PASS', date: 1596791666000, statistic: [], money: 2568912357893},
{key: 3, name: 'xiaohuai', status: 'REJECT', statistic: [], money: 6235871},
{key: 4, name: '陈公子', age: 21, status: 'REAPPLY', date: 1596791666000, statistic: []},
] const config = {
columns,
dataSource,
hasCheck: true, //是否显示表格第一列的checkbox复选框
getCheckboxProps: record => {return {disabled: record.status == 'REJECT'}} //table表格rowSelection的禁用
} //点击获取通过checkbox复选框选中的表格
const childRef = useRef();
const getTableChecked = () => {
const selectedRowKeys = childRef.current.getSelectedRowKeys(), selectedRows = childRef.current.getSelectedRows();
console.log(selectedRowKeys)
console.log(selectedRows)
} return <div>
<Table {...config} cRef={childRef} />
<Button type="primary" onClick={getTableChecked}>获取选择的列表项</Button>
</div>
} export default TableDemo

最后再贴一下本次封装所用到的各个包的版本:

react: 16.8.6,

react-dom: 16.8.6,

react-router-dom: 5.0.0,

antd: 4.3.5,

@babel/core: 7.4.4,

babel-loader: 8.0.5

其实最主要的是react和antd的版本,其中antd4和antd3在table组件上的差异还是很大的,在其他组件上的差异也是很大的。

封装react antd的表格table组件的更多相关文章

  1. 封装React AntD的dialog弹窗组件

    前一段时间分享了基于vue和element所封装的弹窗组件(封装Vue Element的dialog弹窗组件),今天就来分享一个基于react和antD所封装的弹窗组件,反正所使用的技术还是那个技术, ...

  2. 封装react antd的form表单组件

    form表单在我们日常的开发过程中被使用到的概率还是很大的,比如包含了登录.注册.修改个人信息.新增修改业务数据等的公司内部管理系统.而在使用时这些表单的样式如高度.上下边距.边框.圆角.阴影.高亮等 ...

  3. 封装react antd的upload上传组件

    上传文件也是我们在实际开发中常遇到的功能,比如上传产品图片以供更好地宣传我们的产品,上传excel文档以便于更好地展示更多的产品信息,上传zip文件以便于更好地收集一些资料信息等等.至于为何要把上传组 ...

  4. React中使用Ant Table组件

    一.Ant Design of React http://ant.design/docs/react/introduce 二.建立webpack工程 webpack+react demo下载 项目的启 ...

  5. react引用ant的table组件

    import React from 'react';import '../../css/uicss/UI.css';import 'antd/lib/style/index.less';import ...

  6. React antd如何实现<Upload>组件上传附件再次上传已清除附件缓存问题。

    最近在公司做React+antd的项目,遇到一个上传组件的问题,即上传附件成功后,文件展示处仍然还有之前上传附件的缓存信息,需要解决的问题是,要把上一次上传的附件缓存在上传成功或者取消后,可以进行清除 ...

  7. 十九、React UI框架Antd(Ant Design)的使用——及react Antd的使用 button组件 Icon组件 Layout组件 DatePicker日期组件

    一.Antd(Ant Design)的使用:引入全部Css样式 1.1 antd官网: https://ant.design/docs/react/introduce-cn 1.2 React中使用A ...

  8. Ant Table组件

    http://www.cnblogs.com/hujunzheng/p/5689650.html React中使用Ant Table组件   v一.Ant Design of React http:/ ...

  9. 解决react使用antd table组件固定表头后,表头和表体列不对齐以及配置fixed固定左右侧后行高度不对齐

    一.固定表头后表体列和表头不对齐 此问题可能在antd3.24.0版本之前都存在,反正3.16.2版本是存在这个问题的,如果是3.24.0之前的版本估计只能通过修改css样式解决. 按照官网说的: 1 ...

随机推荐

  1. INS-40718 和 INS - 30516

    RAC  安装的时候报错, INS-40718 这个是自己填写的  scan name 和 /etc/hosts  里定义的不一致  可以cat   /etc/hosts   看一下 INS - 30 ...

  2. 从一次故障聊聊前端 UI 自动化测试

    背景 事件的起因在于老板最近的两次"故障",一次去年的,一次最近.共同原因都是脚手架在发布平台发布打包时出错,导致线上应用白屏不可用. 最神奇的是,事后多次 Code Review ...

  3. mysql查看各表占磁盘空间

    select TABLE_NAME, concat(truncate(data_length/1024/1024,2),' MB') as data_size, concat(truncate(ind ...

  4. Go语言系列之手把手教你撸一个ORM(一)

    项目地址:https://github.com/yoyofxteam/yoyodata 欢迎星星,感谢 前言:最近在学习Go语言,就出于学习目的手撸个小架子,欢迎提出宝贵意见,项目使用Mysql数据库 ...

  5. Java基础知识_内存

    前述:利用一段较为充足暑假时间,对以前的Java学习进行一个系统性的回顾,对于部分知识点进行记录和积累. Java中的内存 一 Java中的内存划分: Java中内存主要划分为五部分 栈(Stack) ...

  6. state实例

    States是SaltStack中的配置语言,在日常进行配置管理时需要编写大量的States文件. 比如我们需要安装一个包,然后管理一个配置文件,最后保证某个服务正常运行. 这里就需要我们编写一些st ...

  7. laravel 资源控制器方法列表

    以 PostController 控制器的每个方法都有对应的请求方式.路由命名.URL.方法名和业务逻辑约定. HTTP请求方式 URL 控制器方法 路由命名 业务逻辑描述 GET post inde ...

  8. Fortify Audit Workbench 笔记 Path Manipulation

    Path Manipulation Abstract 通过用户输入控制 file system 操作所用的路径,借此攻击者可以访问或修改其他受保护的系统资源. Explanation 当满足以下两个条 ...

  9. mongoose.model第三个参数的问题

    这个是个好问题,之前按照教程做的数据库没有问题,现在自己从新做出现了问题.还好之前有无意中接触了这个知识点,不然感觉真的很难解决. 在检查完所有东西都没错的时候(前端传给req的数据正常,与数据库相符 ...

  10. MacOS下如何设置hosts?

    hosts文件是什么? hosts文件是一个系统文件,其作用就是将一些常用的网址域名与其对应的IP地址建立一个关联“数据库”.当用户在浏览器中输入一个需要登录的网址时,系统会首先自动从Hosts文件中 ...