bee-table
Version:
Table ui component for react
381 lines (359 loc) • 12.7 kB
JavaScript
import React, { Component } from "react";
import PropTypes from 'prop-types';
const prefix = 'u';
/**
* 参数:prefixCls,默认bee-table,用于设置图标的样式
* @param {*} Table
* @param {*} Icon
*/
export default function sort(Table, Icon) {
const IconType = [{
'type':'flat',
'icon':'uf-symlist',
'order':'flatscend',
},{
'type':'up',
'icon':'uf-sortup',
'order':'ascend',
},{
'type':'down',
'icon':'uf-sortdown',
'order':'descend',
}
]
return class SortTable extends Component {
constructor(props) {
super(props);
let flatColumns = this._toFlatColumn(props.columns,-1);
this.state = { data: this.props.data, columns: props.columns,flatColumns:flatColumns };
this._initSort();
}
static defaultProps = {prefixCls:`${prefix}-table`, sort: { mode: "single", backSource: false } }; //默认是前端排序,值为true为后端排序
static propTypes = {
columns: PropTypes.any,
sort: PropTypes.any,
data: PropTypes.any,
onDropBorder: PropTypes.bool,
}
componentWillReceiveProps(nextProps) {
if (nextProps.columns !== this.props.columns) {
let flatColumns = this._toFlatColumn(nextProps.columns,-1);
this.setState({ columns: nextProps.columns ,flatColumns});
}
if (nextProps.data !== this.props.data) {
this.setState({
data: nextProps.data,
oldData: nextProps.data.concat()
}, function(){
this._initSort(); // 数据更新后需要重新排序
});
}
}
//初始化或data数据变化时重新依据排序状态进行排序
_initSort = () => {
const {sort} = this.props;
const {flatColumns} = this.state;
let needSort = false;
flatColumns.forEach(item => {
if(item.order == 'descend' || item.order == 'ascend') {
needSort = true;
return
}
})
if(needSort) {
if (sort && !sort.backSource && sort.mode !== "single") {//多列排序情况下数据排序
let data = this.multiSort(flatColumns)
this.setState({data})
}else{
//单列排序情况下如果data受控会出现死循环,需要重新考虑
}
}
}
/**
*column扁平化处理,适应多表头避免递归操作
*
*/
_toFlatColumn(columns,parentIndex = -1,flatColumns) {
const _this = this;
let children = [];
flatColumns = flatColumns||[];
// const flatColumns = _this.state;
columns.forEach((item,index)=>{
item.parentIndex = parentIndex;
children = item.children;
flatColumns.push(item);
if(children){
// item.children = [];
_this._toFlatColumn(children,flatColumns.length - 1,flatColumns);
}
});
return flatColumns;
}
getOrderNum = () => {
let orderNum = 0;
//todo 1
this.state.flatColumns.forEach((item, index) => {
if (item.order == "ascend" || item.order == "descend") {
orderNum++;
}
});
return orderNum ? orderNum : 1;
};
/**
* column 当前的排序的列
* 当有的列不排序时,将该列的orderNum置为‘’,并动态的修改其他列的orderNum。
*/
changeOrderNum = column => {
let { flatColumns } = this.state;
//todo 2
flatColumns.forEach(col => {
if (col.orderNum > column.orderNum) {
col.orderNum--;
}
if (column.key == col.key) {
col.orderNum = "";
}
});
this.setState({ flatColumns });
};
/**
* 获取排序字段
*/
getOrderCols = columns => {
let orderCols = [];
//todo 3
columns.forEach(item => {
if (item.order == "ascend" || item.order == "descend") {
orderCols.push({
order: item.order,
field: item.dataIndex,
orderNum: item.orderNum
});
}
});
return orderCols;
};
/**
* pre:前一条数据
* after:后一条数据
* orderType:升序、降序
*/
_sortBy = (pre, after, orderCols, orderColslen, currentIndex) => {
const currentCol = orderCols[currentIndex];
const getMultiSorterValueFunc = currentCol.getMultiSorterValue
let preKey = pre[currentCol.key];
let afterKey = after[currentCol.key];
if (getMultiSorterValueFunc) {
preKey = getMultiSorterValueFunc(pre, currentCol)
afterKey = getMultiSorterValueFunc(after, currentCol)
}
let colSortFun = currentCol.sorter;
if(typeof colSortFun !== 'function'){
colSortFun = () => preKey - afterKey;
}
if (preKey == afterKey && currentIndex + 1 <= orderColslen) {
return this._sortBy(pre, after, orderCols, orderColslen, currentIndex + 1);
}
if (currentCol.order == "ascend") {
return colSortFun(pre,after);
} else {
return -colSortFun(pre,after);
}
};
/**
* 多列排序 先排order为1的,其他的基于已排序的数据排
*/
multiSort = columns => {
let { data, oldData=[] } = this.state;
const self = this;
let orderCols = {},
orderColslen = 0;
//todo 4
columns.forEach(item => {
if (item.orderNum) {
orderColslen++;
orderCols[item.orderNum] = item;
}
});
if (orderColslen > 0) {
data = data.sort(function(a, b) {
return self._sortBy(a, b, orderCols, orderColslen, 1);
});
} else {
data = oldData.concat();
}
return data;
};
toggleSortOrder = (order, column) => {
let { data, oldData = [], flatColumns } = this.state;
let { sort } = this.props;
let seleObj;
if (!oldData.length) {
oldData = data.concat();
}
let sortCol ;
//单列排序,清空其他列的排序
if (sort.mode == "single") {
//todo 5
flatColumns.forEach(da => {
if (da.key == column.key) {
seleObj = da;
} else {
if (da.order) {
da.order = "flatscend";//还原排序状态
}
}
});
seleObj.order = order;//当前排序列状态
sortCol = [{ order: order, field: seleObj.dataIndex }]
//通过后端请求
if (sort.backSource && typeof sort.sortFun === "function") {
//获取排序的字段和方式
sort.sortFun(sortCol);
} else {
if (order === "ascend") {
data = data.sort(function(a, b) {
return typeof column.sorter=='function'&&column.sorter(a, b);
});
} else if (order === "descend") {
data = data.sort(function(a, b) {
return typeof column.sorter=='function'&&column.sorter(b, a);
});
} else {
data = oldData.concat();
}
typeof sort.sortFun === "function" && sort.sortFun(sortCol,data,oldData);
}
} else {//多列排序
seleObj = flatColumns.find(da => da.key == column.key);
seleObj.order = order;
if (order === "flatscend") {
this.changeOrderNum(column);
}
if (!seleObj.orderNum && (order == "ascend" || order == "descend")) {
seleObj.orderNum = this.getOrderNum();
}
sortCol = this.getOrderCols(flatColumns);
if (sort.backSource && typeof sort.sortFun === "function") {
sort.sortFun(sortCol);
} else {
data = this.multiSort(flatColumns);
typeof sort.sortFun === "function" && sort.sortFun(sortCol,data,oldData);
}
}
this.setState({ data, oldData, flatColumns });
};
//每个column上添加orderNum属性,不排序时为“”。
//点击时orderNum有值则不重新赋值,如果没有值,则取当前column下的有oderNum的length值。并排序
//点击置为“”时,动态的设置相关column的orderNum值。并排序
renderColumnsDropdown = columns => {
let tempColumns = [],rsColumns = [];
tempColumns = columns.map(originColumn => {
let column = Object.assign({}, originColumn);
return this.sortColumn(column);
});
rsColumns = this._flatToColumn(tempColumns);
return rsColumns;
};
sortColumn = (column) => {
const { mode } = this.props.sort;
const {prefixCls} = this.props;
let iconTypeIndex = 0;
let sorterClass = "flat";
if (column.order === "ascend") {
iconTypeIndex = 1;
sorterClass = "up";
} else if (column.order === "descend") {
iconTypeIndex = 2;
sorterClass = "down";
}
let sortButton;
// sorter和sortEnable均可触发排序,且sorter优先级更高
if (column.sorter || column.sortEnable ) {
//大于0说明不是升序就是降序,判断orderNum有没有值,没有值赋值
if ( column.sortEnable && !column.sorter) {
switch(column.fieldType){
case 'number':{
column.sorter = this.numberSortFn(column.dataIndex);
break;
}
case 'stringChinese':{
column.sorter = this.chineseSortFn(column.dataIndex);
break;
}
default:{
column.sorter = this.defaultSortFn(column.dataIndex);
break;
}
}
}
if (iconTypeIndex > 0 && !column.orderNum && mode == "multiple") {
column.orderNum = this.getOrderNum();
}
sortButton = <div className={`${prefix}-table-column-sorter`}>
<span className={`${prefix}-table-column-sorter-${sorterClass}`} onClick={() => {
this.toggleSortOrder(IconType[iconTypeIndex == 2 ? 0 : iconTypeIndex + 1].order, column);
if (column.sorterClick) {
column.sorterClick(column, IconType[iconTypeIndex].type);
}
}}>
{/* <Icon type='{IconType[iconTypeIndex].icon}' /> */}
<i className={`uf ${IconType[iconTypeIndex].icon}`} />
<span>{column.orderNum}</span>
</span>
</div>;
}
column.title = <span>
{column.title}
{sortButton}
</span>;
return column;
};
// 默认的比较函数,即字符串比较函数
defaultSortFn = (key) => (a, b)=> {
return a[key] >= b[key] ? 1 : -1;
}
// 数值比较函数
numberSortFn = (key) => (a, b)=> {
let numberA = parseFloat(a[key]);
let numberB = parseFloat(b[key]);
return numberA >= numberB ? 1 : -1;
}
// 中文比较函数,按拼音排序
chineseSortFn = (key) => (a, b)=>{
return a[key].localeCompare(b[key], 'zh-Hans-CN',{sensitivity: 'accent'});
}
_flatToColumn(flatColumns){
const colLen = flatColumns.length;
let parentIndex,rsColumns = [];
//每次渲染需要将父类的children置空,避免重复
flatColumns.forEach(item=>{
if(item.children){
item.children = [];
}
})
for(let i = colLen-1;i>=0;i--){
parentIndex = flatColumns[i].parentIndex;
if(parentIndex >= 0){
flatColumns[parentIndex].children.unshift(flatColumns[i]);
}
}
rsColumns = flatColumns.filter(item=>{
return item.parentIndex == -1
})
return rsColumns;
}
//列宽度拖拽后需要更新sort组件的state.columns数据(否则点了排序后被拖拽的列宽度会被还原)
handleDropBorder=(event,newWidth,newColumn,newColumns)=>{
const {onDropBorder} = this.props;
let flatColumn = this.state.flatColumns.find(column=>column.dataIndex==newColumn.dataIndex);
flatColumn.width = newWidth;
this.setState({flatColumns:this.state.flatColumns});
typeof onDropBorder=='function' && onDropBorder(event,newWidth,newColumn,newColumns);
}
render() {
let columns = this.renderColumnsDropdown(this.state.flatColumns.concat());
return <Table {...this.props} columns={columns} data={this.state.data} onDropBorder={this.handleDropBorder}/>;
}
};
}