1281 lines
43 KiB
JavaScript
1281 lines
43 KiB
JavaScript
import React, { Component } from 'react';
|
||
import PropTypes from 'prop-types';
|
||
import classes from 'component-classes';
|
||
import TableRow from './TableRow';
|
||
import TableHeader from './TableHeader';
|
||
import { measureScrollbar, debounce, warningOnce ,getMaxColChildrenLength} from './utils';
|
||
import shallowequal from 'shallowequal';
|
||
import addEventListener from 'tinper-bee-core/lib/addEventListener';
|
||
import ColumnManager from './ColumnManager';
|
||
import createStore from './createStore';
|
||
import Loading from 'bee-loading';
|
||
import Icon from 'bee-icon';
|
||
import { Event,EventUtil,closest} from "./utils";
|
||
|
||
const propTypes = {
|
||
data: PropTypes.array,
|
||
expandIconAsCell: PropTypes.bool,
|
||
defaultExpandAllRows: PropTypes.bool,
|
||
expandedRowKeys: PropTypes.array,
|
||
defaultExpandedRowKeys: PropTypes.array,
|
||
useFixedHeader: PropTypes.bool,
|
||
columns: PropTypes.array,
|
||
clsPrefix: PropTypes.string,
|
||
bodyStyle: PropTypes.object,
|
||
style: PropTypes.object,
|
||
//特殊的渲染规则的key值
|
||
rowKey: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||
rowClassName: PropTypes.func,
|
||
expandedRowClassName: PropTypes.func,
|
||
childrenColumnName: PropTypes.string,
|
||
onExpand: PropTypes.func,
|
||
onRowHover:PropTypes.func,
|
||
onExpandedRowsChange: PropTypes.func,
|
||
indentSize: PropTypes.number,
|
||
onRowClick: PropTypes.func,
|
||
onRowDoubleClick: PropTypes.func,
|
||
expandIconColumnIndex: PropTypes.number,
|
||
//是否显示表头
|
||
showHeader: PropTypes.bool,
|
||
title: PropTypes.func,
|
||
footer: PropTypes.func,
|
||
emptyText: PropTypes.func,
|
||
scroll: PropTypes.object,
|
||
rowRef: PropTypes.func,
|
||
getBodyWrapper: PropTypes.func,
|
||
children: PropTypes.node,
|
||
draggable: PropTypes.bool,
|
||
minColumnWidth: PropTypes.number,
|
||
filterable: PropTypes.bool,
|
||
filterDelay: PropTypes.number,
|
||
onFilterChange: PropTypes.func,
|
||
onFilterClear: PropTypes.func,
|
||
syncHover: PropTypes.bool,
|
||
tabIndex:PropTypes.string,
|
||
hoverContent:PropTypes.func,
|
||
size: PropTypes.oneOf(['sm', 'md', 'lg']),
|
||
rowDraggAble: PropTypes.bool,
|
||
};
|
||
|
||
const defaultProps = {
|
||
data: [],
|
||
useFixedHeader: false,
|
||
expandIconAsCell: false,
|
||
defaultExpandAllRows: false,
|
||
defaultExpandedRowKeys: [],
|
||
rowKey: 'key',
|
||
rowClassName: () => '',
|
||
expandedRowClassName: () => '',
|
||
onExpand() { },
|
||
onExpandedRowsChange() { },
|
||
onRowClick() { },
|
||
onRowDoubleClick() { },
|
||
clsPrefix: 'u-table',
|
||
bodyStyle: {},
|
||
style: {},
|
||
childrenColumnName: 'children',
|
||
indentSize: 15,
|
||
expandIconColumnIndex: 0,
|
||
showHeader: true,
|
||
scroll: {},
|
||
rowRef: () => null,
|
||
getBodyWrapper: body => body,
|
||
emptyText: () => <Icon type="uf-nodata" className="table-nodata"></Icon>,
|
||
columns:[],
|
||
minColumnWidth: 80,
|
||
locale:{},
|
||
syncHover: true,
|
||
setRowHeight:()=>{},
|
||
setRowParentIndex:()=>{},
|
||
tabIndex:'0',
|
||
heightConsistent:false,
|
||
size: 'md',
|
||
rowDraggAble:false
|
||
};
|
||
|
||
class Table extends Component {
|
||
constructor(props) {
|
||
super(props);
|
||
let expandedRowKeys = [];
|
||
let rows = [...props.data];
|
||
this.columnManager = new ColumnManager(props.columns, props.children, props.originWidth);
|
||
this.store = createStore({ currentHoverKey: null });
|
||
this.firstDid = true;
|
||
if (props.defaultExpandAllRows) {
|
||
for (let i = 0; i < rows.length; i++) {
|
||
const row = rows[i];
|
||
expandedRowKeys.push(this.getRowKey(row, i));
|
||
rows = rows.concat(row[props.childrenColumnName] || []);
|
||
}
|
||
} else {
|
||
expandedRowKeys = props.expandedRowKeys || props.defaultExpandedRowKeys;
|
||
}
|
||
this.state = {
|
||
expandedRowKeys,
|
||
data: props.data,
|
||
currentHoverKey: null,
|
||
scrollPosition: 'left',
|
||
fixedColumnsHeadRowsHeight: [],
|
||
fixedColumnsBodyRowsHeight: [],
|
||
}
|
||
|
||
this.onExpandedRowsChange = this.onExpandedRowsChange.bind(this);
|
||
this.onExpanded = this.onExpanded.bind(this);
|
||
this.onRowDestroy = this.onRowDestroy.bind(this);
|
||
this.getRowKey = this.getRowKey.bind(this);
|
||
this.getExpandedRows = this.getExpandedRows.bind(this);
|
||
this.getHeader = this.getHeader.bind(this);
|
||
this.getHeaderRows = this.getHeaderRows.bind(this);
|
||
this.getExpandedRow = this.getExpandedRow.bind(this);
|
||
this.getRowsByData = this.getRowsByData.bind(this);
|
||
this.getRows = this.getRows.bind(this);
|
||
this.getColGroup = this.getColGroup.bind(this);
|
||
this.getLeftFixedTable = this.getLeftFixedTable.bind(this);
|
||
this.getRightFixedTable = this.getRightFixedTable.bind(this);
|
||
this.getTable = this.getTable.bind(this);
|
||
this.getTitle = this.getTitle.bind(this);
|
||
this.getFooter = this.getFooter.bind(this);
|
||
this.getEmptyText = this.getEmptyText.bind(this);
|
||
this.getHeaderRowStyle = this.getHeaderRowStyle.bind(this);
|
||
this.syncFixedTableRowHeight = this.syncFixedTableRowHeight.bind(this);
|
||
this.resetScrollX = this.resetScrollX.bind(this);
|
||
this.findExpandedRow = this.findExpandedRow.bind(this);
|
||
this.isRowExpanded = this.isRowExpanded.bind(this);
|
||
this.detectScrollTarget = this.detectScrollTarget.bind(this);
|
||
this.handleBodyScroll = this.handleBodyScroll.bind(this);
|
||
this.handleRowHover = this.handleRowHover.bind(this);
|
||
this.computeTableWidth = this.computeTableWidth.bind(this);
|
||
this.onBodyMouseLeave = this.onBodyMouseLeave.bind(this);
|
||
}
|
||
|
||
componentDidMount() {
|
||
EventUtil.addHandler(this.contentTable,'keydown',this.onKeyDown);
|
||
EventUtil.addHandler(this.contentTable,'focus',this.onFocus);
|
||
setTimeout(this.resetScrollX, 300);
|
||
//含有纵向滚动条
|
||
if(this.props.scroll.y){
|
||
this.scrollbarWidth = measureScrollbar();
|
||
}
|
||
//后续也放在recevice里面
|
||
if (!this.props.originWidth) {
|
||
this.computeTableWidth();
|
||
}
|
||
if (this.columnManager.isAnyColumnsFixed()) {
|
||
this.syncFixedTableRowHeight();
|
||
this.resizeEvent = addEventListener(
|
||
window, 'resize', this.resize
|
||
);
|
||
}
|
||
|
||
}
|
||
|
||
componentWillReceiveProps(nextProps) {
|
||
if ('data' in nextProps) {
|
||
this.setState({
|
||
data: nextProps.data,
|
||
});
|
||
}
|
||
if ('expandedRowKeys' in nextProps) {
|
||
this.setState({
|
||
expandedRowKeys: nextProps.expandedRowKeys,
|
||
});
|
||
}
|
||
if (nextProps.columns && nextProps.columns !== this.props.columns) {
|
||
this.columnManager.reset(nextProps.columns);
|
||
if(nextProps.columns.length !== this.props.columns.length && this.refs && this.refs.bodyTable){
|
||
this.scrollTop = this.refs.bodyTable.scrollTop;
|
||
}
|
||
} else if (nextProps.children !== this.props.children) {
|
||
this.columnManager.reset(null, nextProps.children);
|
||
}
|
||
//适配lazyload
|
||
if(nextProps.scrollTop > -1){
|
||
// this.refs.bodyTable.scrollTop = nextProps.scrollTop;
|
||
this.scrollTop = nextProps.scrollTop;
|
||
}
|
||
if (!nextProps.originWidth) {
|
||
this.computeTableWidth();
|
||
this.firstDid = true;//避免重复update
|
||
}
|
||
if(nextProps.resetScroll){
|
||
this.resetScrollX();
|
||
}
|
||
|
||
// console.log('this.scrollTop**********',this.scrollTop);
|
||
|
||
}
|
||
|
||
componentDidUpdate(prevProps) {
|
||
|
||
if (this.columnManager.isAnyColumnsFixed()) {
|
||
this.syncFixedTableRowHeight();
|
||
}
|
||
//适应模态框中表格、以及父容器宽度变化的情况
|
||
if (typeof (this.props.scroll.x) !== 'number' && this.contentTable.getBoundingClientRect().width !== this.contentDomWidth && this.firstDid) {
|
||
this.computeTableWidth();
|
||
this.firstDid = false;//避免重复update
|
||
}
|
||
if(this.scrollTop > -1){
|
||
this.refs.fixedColumnsBodyLeft && ( this.refs.fixedColumnsBodyLeft.scrollTop = this.scrollTop);
|
||
this.refs.fixedColumnsBodyRight && ( this.refs.fixedColumnsBodyRight.scrollTop = this.scrollTop);
|
||
this.refs.bodyTable.scrollTop = this.scrollTop;
|
||
this.scrollTop = -1;
|
||
}
|
||
if (prevProps.data.length === 0 || this.props.data.length === 0 ) {
|
||
this.resetScrollX();
|
||
}
|
||
// 是否传入 scroll中的y属性,如果传入判断是否是整数,如果是则进行比较 。bodyTable 的clientHeight进行判断
|
||
this.isShowScrollY();
|
||
}
|
||
|
||
componentWillUnmount() {
|
||
EventUtil.removeHandler(this.contentTable,'keydown',this.onKeyDown);
|
||
EventUtil.removeHandler(this.contentTable,'focus',this.onFocus);
|
||
if (this.resizeEvent) {
|
||
this.resizeEvent.remove();
|
||
}
|
||
}
|
||
|
||
resize = ()=>{
|
||
debounce(this.syncFixedTableRowHeight, 150);
|
||
this.computeTableWidth();
|
||
let renderFlag = this.state.renderFlag;
|
||
this.setState({
|
||
renderFlag: !renderFlag
|
||
});
|
||
}
|
||
computeTableWidth() {
|
||
|
||
//如果用户传了scroll.x按用户传的为主
|
||
let setWidthParam = this.props.scroll.x
|
||
|
||
if (typeof (setWidthParam) == 'number') {
|
||
let numSetWidthParam = parseInt(setWidthParam);
|
||
this.contentWidth = numSetWidthParam;
|
||
} else {
|
||
// this.preContentDomWidth = this.contentDomWidth;
|
||
//计算总表格宽度、根据表格宽度和各列的宽度和比较,重置最后一列
|
||
this.contentDomWidth = this.contentTable.getBoundingClientRect().width//表格容器宽度
|
||
|
||
this.contentWidth = this.contentDomWidth;//默认与容器宽度一样
|
||
|
||
}
|
||
const computeObj = this.columnManager.getColumnWidth(this.contentWidth);
|
||
let lastShowIndex = computeObj.lastShowIndex;
|
||
this.computeWidth = computeObj.computeWidth;
|
||
|
||
this.domWidthDiff = this.contentDomWidth - this.computeWidth;
|
||
if (typeof (setWidthParam) == 'string' && setWidthParam.indexOf('%')) {
|
||
this.contentWidth = this.contentWidth * parseInt(setWidthParam) / 100;
|
||
this.domWidthDiff = this.contentDomWidth - this.contentWidth;
|
||
}
|
||
|
||
if (this.computeWidth < this.contentWidth) {
|
||
let contentWidthDiff = this.scrollbarWidth?this.contentWidth - this.computeWidth-this.scrollbarWidth:this.contentWidth - this.computeWidth;
|
||
//bordered的表格需要减去边框的差值1
|
||
if(this.props.bordered){
|
||
contentWidthDiff = contentWidthDiff-1;
|
||
}
|
||
this.setState({ contentWidthDiff, lastShowIndex });
|
||
} else {
|
||
this.contentWidth = this.computeWidth;
|
||
this.setState({ contentWidthDiff: 0, lastShowIndex });//重新渲染,为了显示滚动条
|
||
}
|
||
}
|
||
//根据内容动态的判断是否显示纵向滚动条
|
||
isShowScrollY(){
|
||
const props = this.props;
|
||
const y = props.scroll && props.scroll.y;
|
||
if(y){
|
||
const bodyH = this.refs.bodyTable.clientHeight;
|
||
const bodyContentH = this.refs.bodyTable.querySelector('table').clientHeight;
|
||
const rightBodyTable = this.refs.fixedColumnsBodyRight;
|
||
const overflowy = bodyContentH <= bodyH ? 'auto':'scroll';
|
||
this.refs.bodyTable.style.overflowY = overflowy;
|
||
this.refs.headTable.style.overflowY = overflowy;
|
||
rightBodyTable && (rightBodyTable.style.overflowY = overflowy);
|
||
|
||
}
|
||
}
|
||
onExpandedRowsChange(expandedRowKeys) {
|
||
if (!this.props.expandedRowKeys) {
|
||
this.setState({ expandedRowKeys });
|
||
}
|
||
this.props.onExpandedRowsChange(expandedRowKeys);
|
||
}
|
||
|
||
onExpanded(expanded, record, index, e) {
|
||
if (e) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
}
|
||
const info = this.findExpandedRow(record);
|
||
if (typeof info !== 'undefined' && !expanded) {
|
||
this.onRowDestroy(record, index);
|
||
} else if (!info && expanded) {
|
||
const expandedRows = this.getExpandedRows().concat();
|
||
expandedRows.push(this.getRowKey(record, index));
|
||
this.onExpandedRowsChange(expandedRows);
|
||
}
|
||
this.props.onExpand(expanded, record,index);
|
||
}
|
||
|
||
onRowDestroy(record, rowIndex) {
|
||
const expandedRows = this.getExpandedRows().concat();
|
||
const rowKey = this.getRowKey(record, rowIndex);
|
||
let index = -1;
|
||
expandedRows.forEach((r, i) => {
|
||
if (r === rowKey) {
|
||
index = i;
|
||
}
|
||
});
|
||
if (index !== -1) {
|
||
expandedRows.splice(index, 1);
|
||
}
|
||
//
|
||
if(this.currentHoverKey == rowKey && this.hoverDom){
|
||
this.hoverDom.style.display = 'none';
|
||
}
|
||
this.onExpandedRowsChange(expandedRows);
|
||
}
|
||
|
||
getRowKey(record, index) {
|
||
const rowKey = this.props.rowKey;
|
||
const key = (typeof rowKey === 'function') ?
|
||
rowKey(record, index) : record[rowKey];
|
||
warningOnce(
|
||
key !== undefined,
|
||
'Each record in table should have a unique `key` prop,' +
|
||
'or set `rowKey` to an unique primary key.'
|
||
);
|
||
return key;
|
||
|
||
|
||
}
|
||
|
||
getExpandedRows() {
|
||
return this.props.expandedRowKeys || this.state.expandedRowKeys;
|
||
}
|
||
|
||
getHeader(columns, fixed) {
|
||
const { filterDelay, onFilterChange, onFilterClear, filterable, showHeader, expandIconAsCell, clsPrefix, onDragStart, onDragEnter, onDragOver, onDrop, draggable,
|
||
onMouseDown, onMouseMove, onMouseUp, dragborder, onThMouseMove, dragborderKey, minColumnWidth, headerHeight,afterDragColWidth,headerScroll ,bordered,onDropBorder} = this.props;
|
||
const rows = this.getHeaderRows(columns);
|
||
if (expandIconAsCell && fixed !== 'right') {
|
||
rows[0].unshift({
|
||
key: 'u-table-expandIconAsCell',
|
||
className: `${clsPrefix}-expand-icon-th`,
|
||
title: '',
|
||
rowSpan: rows.length,
|
||
});
|
||
}
|
||
|
||
const trStyle = headerHeight&&!fixed ? { height: headerHeight } : (fixed ? this.getHeaderRowStyle(columns, rows) : null);
|
||
let drop = draggable ? { onDragStart, onDragOver, onDrop, onDragEnter, draggable } : {};
|
||
let dragBorder = dragborder ? { onMouseDown, onMouseMove, onMouseUp, dragborder, onThMouseMove, dragborderKey,onDropBorder } : {};
|
||
let contentWidthDiff = 0;
|
||
//非固定表格,宽度不够时自动扩充
|
||
if (!fixed) {
|
||
contentWidthDiff = this.state.contentWidthDiff
|
||
}
|
||
return showHeader ? (
|
||
<TableHeader
|
||
{...drop}
|
||
{...dragBorder}
|
||
locale={this.props.locale}
|
||
minColumnWidth={minColumnWidth}
|
||
contentWidthDiff={contentWidthDiff}
|
||
contentWidth={this.contentWidth}
|
||
lastShowIndex={this.state.lastShowIndex}
|
||
clsPrefix={clsPrefix}
|
||
rows={rows}
|
||
contentTable={this.contentTable}
|
||
rowStyle={trStyle}
|
||
fixed={fixed}
|
||
filterable={filterable}
|
||
onFilterChange={onFilterChange}
|
||
onFilterClear={onFilterClear}
|
||
filterDelay={filterDelay}
|
||
afterDragColWidth = {afterDragColWidth}
|
||
contentDomWidth={this.contentDomWidth}
|
||
scrollbarWidth = {this.scrollbarWidth}
|
||
headerScroll = {headerScroll}
|
||
bordered = {bordered}
|
||
/>
|
||
) : null;
|
||
}
|
||
|
||
getHeaderRows(columns, currentRow = 0, rows) {
|
||
let { contentWidthDiff = 0, lastShowIndex = -1 } = this.state;
|
||
let filterCol = [];
|
||
rows = rows || [];
|
||
rows[currentRow] = rows[currentRow] || [];
|
||
|
||
columns.forEach((column,i) => {
|
||
if (column.rowSpan && rows.length < column.rowSpan) {
|
||
while (rows.length < column.rowSpan) {
|
||
rows.push([]);
|
||
}
|
||
}
|
||
let width = column.width;
|
||
if (typeof (width) == 'string' && width.indexOf('%') > -1 && this.contentWidth) {
|
||
width = parseInt(this.contentWidth * parseInt(width) / 100);
|
||
} else if (width) {
|
||
width = parseInt(width);
|
||
}
|
||
if (lastShowIndex == i && width) {
|
||
width = width + contentWidthDiff;
|
||
}
|
||
const cell = {
|
||
key: column.key,
|
||
className: column.className || '',
|
||
children: column.title,
|
||
drgHover: column.drgHover,
|
||
fixed: column.fixed,
|
||
width: width,
|
||
dataindex:column.dataIndex,
|
||
textAlign:column.textAlign
|
||
};
|
||
if (column.onHeadCellClick) {
|
||
cell.onClick = column.onHeadCellClick;
|
||
}
|
||
if (column.children) {
|
||
this.getHeaderRows(column.children, currentRow + 1, rows);
|
||
}
|
||
if ('colSpan' in column) {
|
||
cell.colSpan = column.colSpan;
|
||
}
|
||
if ('rowSpan' in column) {
|
||
cell.rowSpan = column.rowSpan;
|
||
}
|
||
if (cell.colSpan !== 0) {
|
||
rows[currentRow].push(cell);
|
||
}
|
||
//判断是否启用过滤
|
||
if (this.props.filterable) {
|
||
//组装Filter需要的Col
|
||
filterCol.push({
|
||
key: column.key,
|
||
children: "过滤渲染",
|
||
width: column.width,
|
||
filtertype: column.filterType,//下拉的类型 包括['text','dropdown','date','daterange','number']
|
||
dataindex: column.dataIndex,//field
|
||
datasource: this.props.data,//需要单独拿到数据处理
|
||
format: column.format,//设置日期的格式
|
||
filterdropdown: column.filterDropdown,//是否显示 show hide
|
||
filterdropdownauto: column.filterDropdownAuto,//是否自定义数据
|
||
filterdropdowndata: column.filterDropdownData,//自定义数据格式
|
||
filterdropdownfocus: column.filterDropdownFocus,//焦点触发函数回调
|
||
filterdropdowntype: column.filterDropdownType,//下拉的类型分为 String,Number 默认是String
|
||
filterdropdownincludekeys: column.filterDropdownIncludeKeys,//下拉条件按照指定的keys去显示
|
||
filterinputnumberoptions: column.filterInputNumberOptions//设置数值框内的详细属性
|
||
});
|
||
}
|
||
});
|
||
if (this.props.filterable) {
|
||
rows.push(filterCol);
|
||
}
|
||
return rows.filter(row => row.length > 0);
|
||
}
|
||
|
||
getExpandedRow(key, content, visible, className, fixed) {
|
||
const { clsPrefix, expandIconAsCell } = this.props;
|
||
let colCount;
|
||
if (fixed === 'left') {
|
||
colCount = this.columnManager.leftLeafColumns().length;
|
||
} else if (fixed === 'right') {
|
||
colCount = this.columnManager.rightLeafColumns().length;
|
||
} else {
|
||
colCount = this.columnManager.leafColumns().length;
|
||
}
|
||
|
||
function contentContainer() {
|
||
if (content && content.props && content.props.style) {
|
||
return (
|
||
<div style={{ height: content.props.style.height }}></div>
|
||
)
|
||
} else {
|
||
return ' '
|
||
}
|
||
}
|
||
|
||
const columns = [{
|
||
key: 'extra-row',
|
||
render: () => ({
|
||
props: {
|
||
colSpan: colCount,
|
||
},
|
||
children: !fixed ? content : contentContainer(),
|
||
}),
|
||
}];
|
||
if (expandIconAsCell && fixed !== 'right') {
|
||
columns.unshift({
|
||
key: 'expand-icon-placeholder',
|
||
render: () => null,
|
||
});
|
||
}
|
||
return (
|
||
<TableRow
|
||
columns={columns}
|
||
visible={visible}
|
||
className={className}
|
||
key={`${key}-extra-row`}
|
||
clsPrefix={`${clsPrefix}-expanded-row`}
|
||
indent={1}
|
||
expandable={false}
|
||
store={this.store}
|
||
dragborderKey={this.props.dragborderKey}
|
||
rowDraggAble={this.props.rowDraggAble}
|
||
onDragRow={this.onDragRow}
|
||
/>
|
||
);
|
||
}
|
||
|
||
onDragRow = (currentIndex,targetIndex)=>{
|
||
let {data} = this.state,
|
||
currentObj = data[currentIndex],
|
||
targetObj = data[targetIndex];
|
||
console.log(currentIndex+" ----------onRowDragEnd-------- "+targetIndex);
|
||
data.splice(targetIndex, 0, data.splice(currentIndex, 1).shift());
|
||
console.log(" _data---- ",data);
|
||
this.setState({
|
||
data: data,
|
||
});
|
||
}
|
||
|
||
/**
|
||
*
|
||
*
|
||
* @param {*} data
|
||
* @param {*} visible
|
||
* @param {*} indent 层级
|
||
* @param {*} columns
|
||
* @param {*} fixed
|
||
* @param {number} [rootIndex=-1] 祖级节点
|
||
* @returns
|
||
* @memberof Table
|
||
*/
|
||
getRowsByData(data, visible, indent, columns, fixed,rootIndex=-1) {
|
||
const props = this.props;
|
||
const childrenColumnName = props.childrenColumnName;
|
||
const expandedRowRender = props.expandedRowRender;
|
||
const expandRowByClick = props.expandRowByClick;
|
||
const { fixedColumnsBodyRowsHeight } = this.state;
|
||
let rst = [];
|
||
|
||
let height;
|
||
const rowClassName = props.rowClassName;
|
||
const rowRef = props.rowRef;
|
||
const expandedRowClassName = props.expandedRowClassName;
|
||
const needIndentSpaced = props.data.some(record => record[childrenColumnName]);
|
||
const onRowClick = props.onRowClick;
|
||
const onRowDoubleClick = props.onRowDoubleClick;
|
||
|
||
const expandIconAsCell = fixed !== 'right' ? props.expandIconAsCell : false;
|
||
const expandIconColumnIndex = fixed !== 'right' ? props.expandIconColumnIndex : -1;
|
||
if(props.lazyLoad && props.lazyLoad.preHeight && indent == 0){
|
||
rst.push(
|
||
<TableRow height={props.lazyLoad.preHeight} columns={[]} className='' key={'table_row_first'} store={this.store} visible = {true}/>
|
||
)
|
||
}
|
||
const lazyCurrentIndex = props.lazyLoad && props.lazyLoad.startIndex ?props.lazyLoad.startIndex :0;
|
||
const lazyParentIndex = props.lazyLoad && props.lazyLoad.startParentIndex ?props.lazyLoad.startParentIndex :0;
|
||
for (let i = 0; i < data.length; i++) {
|
||
let isHiddenExpandIcon;
|
||
const record = data[i];
|
||
const key = this.getRowKey(record, i);
|
||
const childrenColumn = record[childrenColumnName];
|
||
const isRowExpanded = this.isRowExpanded(record, i);
|
||
let expandedRowContent;
|
||
let expandedContentHeight = 0;
|
||
//fixedIndex一般是跟index是一个值的,只有是树结构时,会讲子节点的值也累计上
|
||
let fixedIndex = i;
|
||
//判断是否是tree结构
|
||
if (this.treeType) {
|
||
fixedIndex = this.treeRowIndex;
|
||
}
|
||
if (expandedRowRender && isRowExpanded) {
|
||
expandedRowContent = expandedRowRender(record, fixedIndex+lazyCurrentIndex, indent);
|
||
expandedContentHeight = parseInt(expandedRowContent.props && expandedRowContent.props.style && expandedRowContent.props.style.height?expandedRowContent.props.style.height:0);
|
||
}
|
||
//只有当使用expandedRowRender参数的时候才去识别isHiddenExpandIcon(隐藏行展开的icon)
|
||
if (expandedRowRender && typeof props.haveExpandIcon == 'function') {
|
||
isHiddenExpandIcon = props.haveExpandIcon(record, i);
|
||
}
|
||
|
||
|
||
const onHoverProps = {};
|
||
|
||
onHoverProps.onHover = this.handleRowHover;
|
||
|
||
|
||
|
||
if (props.height) {
|
||
height = props.height
|
||
} else if(fixed || props.heightConsistent) {
|
||
height = fixedColumnsBodyRowsHeight[fixedIndex];
|
||
}
|
||
|
||
let leafColumns;
|
||
if (fixed === 'left') {
|
||
leafColumns = this.columnManager.leftLeafColumns();
|
||
} else if (fixed === 'right') {
|
||
leafColumns = this.columnManager.rightLeafColumns();
|
||
} else {
|
||
leafColumns = this.columnManager.leafColumns();
|
||
}
|
||
let className = rowClassName(record, fixedIndex+lazyCurrentIndex, indent);
|
||
|
||
//合计代码如果是最后一行并且有合计功能时,最后一行为合计列
|
||
if(i == data.length -1 && props.showSum){
|
||
className = className + ' sumrow';
|
||
}
|
||
|
||
let paramRootIndex = rootIndex;
|
||
//小于0说明为第一层节点,她的子孙节点要保存自己的根节点
|
||
if(paramRootIndex<0){
|
||
paramRootIndex = i+lazyParentIndex;
|
||
}
|
||
let index = i;
|
||
if(rootIndex ==-1){
|
||
index = i+lazyParentIndex
|
||
}
|
||
rst.push(
|
||
<TableRow
|
||
indent={indent}
|
||
indentSize={props.indentSize}
|
||
needIndentSpaced={needIndentSpaced}
|
||
className={className}
|
||
record={record}
|
||
expandIconAsCell={expandIconAsCell}
|
||
onDestroy={this.onRowDestroy}
|
||
index={index}
|
||
visible={visible}
|
||
expandRowByClick={expandRowByClick}
|
||
onExpand={this.onExpanded}
|
||
expandable={childrenColumn || expandedRowRender}
|
||
expanded={isRowExpanded}
|
||
clsPrefix={`${props.clsPrefix}-row`}
|
||
childrenColumnName={childrenColumnName}
|
||
columns={leafColumns}
|
||
expandIconColumnIndex={expandIconColumnIndex}
|
||
onRowClick={onRowClick}
|
||
onRowDoubleClick={onRowDoubleClick}
|
||
height={height}
|
||
isHiddenExpandIcon={isHiddenExpandIcon}
|
||
{...onHoverProps}
|
||
key={"table_row_"+key+"_"+index}
|
||
hoverKey={key}
|
||
ref={rowRef}
|
||
store={this.store}
|
||
fixed={fixed}
|
||
expandedContentHeight={expandedContentHeight}
|
||
setRowHeight={props.setRowHeight}
|
||
setRowParentIndex={props.setRowParentIndex}
|
||
treeType={childrenColumn||this.treeType?true:false}
|
||
fixedIndex={fixedIndex+lazyCurrentIndex}
|
||
rootIndex = {rootIndex}
|
||
syncHover = {props.syncHover}
|
||
bodyDisplayInRow = {props.bodyDisplayInRow}
|
||
rowDraggAble={this.props.rowDraggAble}
|
||
onDragRow={this.onDragRow}
|
||
contentTable={this.contentTable}
|
||
/>
|
||
);
|
||
this.treeRowIndex++;
|
||
const subVisible = visible && isRowExpanded;
|
||
|
||
if (expandedRowContent && isRowExpanded) {
|
||
rst.push(this.getExpandedRow(
|
||
key, expandedRowContent, subVisible, expandedRowClassName(record, i, indent), fixed
|
||
));
|
||
}
|
||
if (childrenColumn) {
|
||
this.treeType = true;//证明是tree表形式visible = {true}
|
||
rst = rst.concat(this.getRowsByData(
|
||
childrenColumn, subVisible, indent + 1, columns, fixed,paramRootIndex
|
||
));
|
||
}
|
||
}
|
||
|
||
if(props.lazyLoad && props.lazyLoad.sufHeight && indent == 0){
|
||
rst.push(
|
||
<TableRow height={props.lazyLoad.sufHeight} key={'table_row_end'} columns={[]} className='' store={this.store} visible = {true}/>
|
||
)
|
||
}
|
||
return rst;
|
||
}
|
||
|
||
getRows(columns, fixed) {
|
||
//统计index,只有含有鼠表结构才有用,因为数表结构时,固定列的索引取值有问题
|
||
this.treeRowIndex = 0;
|
||
let rs = this.getRowsByData(this.state.data, true, 0, columns, fixed);
|
||
return rs;
|
||
}
|
||
|
||
getColGroup(columns, fixed) {
|
||
let cols = [];
|
||
let self = this;
|
||
|
||
let { contentWidthDiff = 0, lastShowIndex = 0 } = this.state;
|
||
if (this.props.expandIconAsCell && fixed !== 'right') {
|
||
cols.push(
|
||
<col
|
||
className={`${this.props.clsPrefix}-expand-icon-col`}
|
||
key="u-table-expand-icon-col"
|
||
/>
|
||
);
|
||
}
|
||
let leafColumns;
|
||
if (fixed === 'left') {
|
||
contentWidthDiff = 0;
|
||
leafColumns = this.columnManager.leftLeafColumns();
|
||
} else if (fixed === 'right') {
|
||
contentWidthDiff = 0;
|
||
leafColumns = this.columnManager.rightLeafColumns();
|
||
} else {
|
||
leafColumns = this.columnManager.leafColumns();
|
||
}
|
||
cols = cols.concat(leafColumns.map((c, i, arr) => {
|
||
let fixedClass ='';
|
||
let width = c.width;
|
||
if (typeof (width) == 'string' && width.indexOf('%') > -1 && self.contentWidth) {
|
||
width = parseInt(self.contentWidth * parseInt(width) / 100);
|
||
} else if (width) {
|
||
width = parseInt(width);
|
||
}
|
||
if (lastShowIndex == i && width) {
|
||
width = width + contentWidthDiff;
|
||
}
|
||
if (!fixed && c.fixed) {
|
||
fixedClass = ` ${this.props.clsPrefix}-row-fixed-columns-in-body`;
|
||
}
|
||
return <col key={c.key} style={{ width: width, minWidth: c.width }} className={fixedClass}/>;
|
||
}));
|
||
return <colgroup id="bee-table-colgroup">{cols}</colgroup>;
|
||
}
|
||
|
||
renderDragHideTable = () => {
|
||
const { columns, dragborder, dragborderKey } = this.props;
|
||
if (!dragborder) return null;
|
||
let sum = 0;
|
||
return (<div id={`u-table-drag-hide-table-${dragborderKey}`} className={`${this.props.clsPrefix}-hiden-drag`} >
|
||
{
|
||
columns.map((da, i) => {
|
||
sum += da.width ? da.width : 0;
|
||
return (<div className={`${this.props.clsPrefix}-hiden-drag-li`} key={da + "_hiden_" + i} style={{ left: sum + "px" }}></div>);
|
||
})
|
||
}
|
||
</div>);
|
||
}
|
||
|
||
getLeftFixedTable() {
|
||
return this.getTable({
|
||
columns: this.columnManager.leftColumns(),
|
||
fixed: 'left',
|
||
});
|
||
}
|
||
|
||
getRightFixedTable() {
|
||
return this.getTable({
|
||
columns: this.columnManager.rightColumns(),
|
||
fixed: 'right',
|
||
});
|
||
}
|
||
|
||
getTable(options = {}) {
|
||
const { columns, fixed } = options;
|
||
const { clsPrefix, scroll = {}, getBodyWrapper, footerScroll,headerScroll } = this.props;
|
||
let { useFixedHeader } = this.props;
|
||
const bodyStyle = { ...this.props.bodyStyle };
|
||
const headStyle = {};
|
||
const innerBodyStyle = {};
|
||
|
||
let tableClassName = '';
|
||
//表格元素的宽度大于容器的宽度也显示滚动条
|
||
if (scroll.x || fixed || this.contentDomWidth < this.contentWidth) {
|
||
tableClassName = `${clsPrefix}-fixed`;
|
||
//没有数据并且含有顶部菜单时
|
||
if(this.props.data.length == 0 && this.props.headerScroll ){
|
||
bodyStyle.overflowX = 'hidden';
|
||
}
|
||
if (!footerScroll) {
|
||
bodyStyle.overflowX = bodyStyle.overflowX || 'auto';
|
||
}
|
||
}
|
||
|
||
if (scroll.y) {
|
||
// maxHeight will make fixed-Table scrolling not working
|
||
// so we only set maxHeight to body-Table here
|
||
if (fixed) {
|
||
// bodyStyle.height = bodyStyle.height || scroll.y;
|
||
innerBodyStyle.maxHeight = bodyStyle.maxHeight || scroll.y;
|
||
innerBodyStyle.overflowY = bodyStyle.overflowY || 'scroll';
|
||
} else {
|
||
bodyStyle.maxHeight = bodyStyle.maxHeight || scroll.y;
|
||
}
|
||
bodyStyle.overflowY = bodyStyle.overflowY || 'scroll';
|
||
useFixedHeader = true;
|
||
|
||
// Add negative margin bottom for scroll bar overflow bug
|
||
const scrollbarWidth = this.scrollbarWidth;
|
||
if (scrollbarWidth >= 0) {
|
||
(fixed ? bodyStyle : headStyle).paddingBottom = '0px';
|
||
//显示表头滚动条
|
||
if(headerScroll){
|
||
if(fixed){
|
||
|
||
if(this.domWidthDiff <= 0){
|
||
headStyle.marginBottom = `${scrollbarWidth}px`;
|
||
// bodyStyle.marginBottom = `-${scrollbarWidth}px`;
|
||
}else{
|
||
innerBodyStyle.overflowX = 'auto';
|
||
}
|
||
}else{
|
||
//内容少,不用显示滚动条
|
||
if(this.domWidthDiff > 0){
|
||
headStyle.overflowX = 'hidden';
|
||
}
|
||
headStyle.marginBottom = `0px`;
|
||
}
|
||
}else{
|
||
if(fixed){
|
||
if(this.domWidthDiff > 0){
|
||
headStyle.overflow = 'hidden';
|
||
innerBodyStyle.overflowX = 'auto'; //兼容expand场景、子表格含有固定列的场景
|
||
}else{
|
||
// bodyStyle.marginBottom = `-${scrollbarWidth}px`;
|
||
}
|
||
|
||
}else{
|
||
headStyle.marginBottom = `-${scrollbarWidth}px`;
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
const renderTable = (hasHead = true, hasBody = true) => {
|
||
const tableStyle = {};
|
||
if (!fixed && scroll.x) {
|
||
// not set width, then use content fixed width
|
||
if (scroll.x === true) {
|
||
tableStyle.tableLayout = 'fixed';
|
||
} else {
|
||
tableStyle.width = this.contentWidth - this.columnManager.getLeftColumnsWidth(this.contentWidth) - this.columnManager.getRightColumnsWidth(this.contentWidth);
|
||
}
|
||
}
|
||
// 自动出现滚动条
|
||
if ( !fixed && this.contentDomWidth < this.contentWidth) {
|
||
tableStyle.width = this.contentWidth - this.columnManager.getLeftColumnsWidth(this.contentWidth) - this.columnManager.getRightColumnsWidth(this.contentWidth);
|
||
}
|
||
const tableBody = hasBody ? getBodyWrapper(
|
||
<tbody className={`${clsPrefix}-tbody`} onMouseLeave={this.onBodyMouseLeave}>
|
||
{this.getRows(columns, fixed)}
|
||
</tbody>
|
||
) : null;
|
||
let _drag_class = this.props.dragborder ? "table-drag-bordered" : ""
|
||
return (
|
||
<table id="bee-table-uid" className={` ${tableClassName} table-bordered ${_drag_class} `} style={tableStyle} >
|
||
{/* {this.props.dragborder?null:this.getColGroup(columns, fixed)} */}
|
||
{this.getColGroup(columns, fixed)}
|
||
{hasHead ? this.getHeader(columns, fixed) : null}
|
||
{tableBody}
|
||
</table>
|
||
);
|
||
};
|
||
|
||
let headTable;
|
||
|
||
if (useFixedHeader) {
|
||
headTable = (
|
||
<div
|
||
className={`${clsPrefix}-header`}
|
||
ref={fixed ? null : 'headTable'}
|
||
style={headStyle}
|
||
onMouseOver={this.detectScrollTarget}
|
||
onTouchStart={this.detectScrollTarget}
|
||
onScroll={this.handleBodyScroll}
|
||
>
|
||
{renderTable(true, false)}
|
||
</div>
|
||
);
|
||
}
|
||
let BodyTable = (
|
||
<div
|
||
className={`${clsPrefix}-body`}
|
||
style={bodyStyle}
|
||
ref="bodyTable"
|
||
onMouseOver={this.detectScrollTarget}
|
||
onTouchStart={this.detectScrollTarget}
|
||
onScroll={this.handleBodyScroll}
|
||
onMouseLeave={this.onBodyMouseLeave}
|
||
>
|
||
{this.renderDragHideTable()}
|
||
{renderTable(!useFixedHeader)}
|
||
</div>
|
||
);
|
||
|
||
if (fixed && columns.length) {
|
||
let refName;
|
||
if (columns[0].fixed === 'left' || columns[0].fixed === true) {
|
||
refName = 'fixedColumnsBodyLeft';
|
||
} else if (columns[0].fixed === 'right') {
|
||
refName = 'fixedColumnsBodyRight';
|
||
}
|
||
delete bodyStyle.overflowX;
|
||
delete bodyStyle.overflowY;
|
||
BodyTable = (
|
||
<div
|
||
className={`${clsPrefix}-body-outer`}
|
||
style={{ ...bodyStyle }}
|
||
>
|
||
<div
|
||
style={{...innerBodyStyle}}
|
||
className={`${clsPrefix}-body-inner`}
|
||
ref={refName}
|
||
onMouseOver={this.detectScrollTarget}
|
||
onTouchStart={this.detectScrollTarget}
|
||
onScroll={this.handleBodyScroll}
|
||
>
|
||
{renderTable(!useFixedHeader)}
|
||
<div className="scroll-dom" style={{height:`${this.scrollbarWidth}px`}}></div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
const leftFixedWidth = this.columnManager.getLeftColumnsWidth(this.contentWidth);
|
||
const rightFixedWidth = this.columnManager.getRightColumnsWidth(this.contentWidth);
|
||
let parStyle = {}
|
||
if(!fixed){
|
||
parStyle = {'marginLeft':leftFixedWidth,'marginRight':rightFixedWidth}
|
||
}
|
||
return <div style={parStyle}>{headTable}{BodyTable}</div>;
|
||
}
|
||
|
||
getTitle() {
|
||
const { title, clsPrefix } = this.props;
|
||
return title ? (
|
||
<div className={`${clsPrefix}-title`}>
|
||
{title(this.state.data)}
|
||
</div>
|
||
) : null;
|
||
}
|
||
|
||
getFooter() {
|
||
const { footer, clsPrefix } = this.props;
|
||
return footer ? (
|
||
<div className={`${clsPrefix}-footer`}>
|
||
{footer(this.state.data)}
|
||
</div>
|
||
) : null;
|
||
}
|
||
|
||
getEmptyText() {
|
||
const { emptyText, clsPrefix, data } = this.props;
|
||
return !data.length ? (
|
||
<div className={`${clsPrefix}-placeholder`}>
|
||
{emptyText()}
|
||
</div>
|
||
) : null;
|
||
}
|
||
|
||
getHeaderRowStyle(columns, rows) {
|
||
const { fixedColumnsHeadRowsHeight } = this.state;
|
||
const headerHeight = fixedColumnsHeadRowsHeight[0];
|
||
|
||
if (headerHeight && columns) {
|
||
if (headerHeight === 'auto') {
|
||
return { height: 'auto' };
|
||
}
|
||
return { height: headerHeight / rows.length };
|
||
}
|
||
return null;
|
||
}
|
||
|
||
syncFixedTableRowHeight() {
|
||
//this.props.height、headerHeight分别为用户传入的行高和表头高度,如果有值,所有行的高度都是固定的,主要为了避免在千行数据中有固定列时获取行高度有问题
|
||
const { clsPrefix, height, headerHeight,columns,heightConsistent } = this.props;
|
||
const headRows = this.refs.headTable ?
|
||
this.refs.headTable.querySelectorAll('thead') :
|
||
this.refs.bodyTable.querySelectorAll('thead');
|
||
const bodyRows = this.refs.bodyTable.querySelectorAll(`.${clsPrefix}-row`) || [];
|
||
const leftBodyRows = this.refs.fixedColumnsBodyLeft && this.refs.fixedColumnsBodyLeft.querySelectorAll(`.${clsPrefix}-row`) || [];
|
||
const rightBodyRows = this.refs.fixedColumnsBodyRight && this.refs.fixedColumnsBodyRight.querySelectorAll(`.${clsPrefix}-row`) || [];
|
||
const fixedColumnsHeadRowsHeight = [].map.call(
|
||
headRows, row =>{
|
||
let height = headerHeight;
|
||
if(headerHeight){
|
||
height = (getMaxColChildrenLength(columns)+1)*headerHeight;
|
||
}
|
||
return headerHeight ? height : (row.getBoundingClientRect().height || 'auto')}
|
||
);
|
||
const fixedColumnsBodyRowsHeight = [].map.call(
|
||
bodyRows, (row,index) =>{
|
||
let rsHeight = height;
|
||
if(rsHeight){
|
||
return rsHeight;
|
||
}else{
|
||
// 为了提高性能,默认获取主表的高度,但是有的场景中固定列的高度比主表的高度高,所以提供此属性,会统计所有列的高度取最大的,设置
|
||
if(heightConsistent){
|
||
let leftHeight,rightHeight,currentHeight,maxHeight;
|
||
leftHeight = leftBodyRows[index]?leftBodyRows[index].getBoundingClientRect().height:0;
|
||
rightHeight = rightBodyRows[index]?rightBodyRows[index].getBoundingClientRect().height:0;
|
||
currentHeight = row.getBoundingClientRect().height
|
||
maxHeight = Math.max(leftHeight,rightHeight,currentHeight);
|
||
return maxHeight || 'auto'
|
||
}else{
|
||
return row.getBoundingClientRect().height || 'auto'
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
);
|
||
|
||
if (shallowequal(this.state.fixedColumnsHeadRowsHeight, fixedColumnsHeadRowsHeight) &&
|
||
shallowequal(this.state.fixedColumnsBodyRowsHeight, fixedColumnsBodyRowsHeight)) {
|
||
return;
|
||
}
|
||
this.setState({
|
||
fixedColumnsHeadRowsHeight,
|
||
fixedColumnsBodyRowsHeight,
|
||
});
|
||
}
|
||
|
||
resetScrollX() {
|
||
if (this.refs.headTable) {
|
||
this.refs.headTable.scrollLeft = 0;
|
||
}
|
||
if (this.refs.bodyTable) {
|
||
this.refs.bodyTable.scrollLeft = 0;
|
||
}
|
||
}
|
||
|
||
findExpandedRow(record, index) {
|
||
const rows = this.getExpandedRows().filter(i => i === this.getRowKey(record, index));
|
||
return rows[0];
|
||
}
|
||
|
||
isRowExpanded(record, index) {
|
||
return typeof this.findExpandedRow(record, index) !== 'undefined';
|
||
}
|
||
onBodyMouseLeave(e){
|
||
this.hideHoverDom(e);
|
||
}
|
||
|
||
detectScrollTarget(e) {
|
||
if (this.scrollTarget !== e.currentTarget) {
|
||
this.scrollTarget = e.currentTarget;
|
||
}
|
||
}
|
||
|
||
hideHoverDom(e){
|
||
if(this.hoverDom){
|
||
this.hoverDom.style.display = 'none';
|
||
}
|
||
}
|
||
|
||
|
||
handleBodyScroll(e) {
|
||
|
||
const { scroll = {},clsPrefix,handleScrollY, handleScrollX} = this.props;
|
||
const { headTable, bodyTable, fixedColumnsBodyLeft, fixedColumnsBodyRight } = this.refs;
|
||
// Prevent scrollTop setter trigger onScroll event
|
||
// http://stackoverflow.com/q/1386696
|
||
if (e.currentTarget !== e.target) {
|
||
return;
|
||
}
|
||
if (e.target.scrollLeft !== this.lastScrollLeft) {
|
||
let position = '';
|
||
if (e.target === bodyTable && headTable) {
|
||
headTable.scrollLeft = e.target.scrollLeft;
|
||
} else if (e.target === headTable && bodyTable) {
|
||
bodyTable.scrollLeft = e.target.scrollLeft;
|
||
}
|
||
if (e.target.scrollLeft === 0) {
|
||
position='left';
|
||
} else if (e.target.scrollLeft + 1 >=
|
||
e.target.children[0].getBoundingClientRect().width -
|
||
e.target.getBoundingClientRect().width) {
|
||
position='right';
|
||
} else if (this.state.scrollPosition !== 'middle') {
|
||
position='middle';
|
||
}
|
||
if(position){
|
||
classes(this.contentTable)
|
||
.remove(new RegExp(`^${clsPrefix}-scroll-position-.+$`))
|
||
.add(`${clsPrefix}-scroll-position-${position}`);
|
||
}
|
||
if(handleScrollX){
|
||
debounce(
|
||
handleScrollX(e.target.scrollLeft,this.treeType),
|
||
300)
|
||
}
|
||
}
|
||
// console.log('lastScrollTop--'+this.lastScrollTop+'--eventScrollTop--'+ e.target.scrollTop);
|
||
if (scroll.y && this.lastScrollTop != e.target.scrollTop && e.target !== headTable) {
|
||
if (fixedColumnsBodyLeft && e.target !== fixedColumnsBodyLeft) {
|
||
fixedColumnsBodyLeft.scrollTop = e.target.scrollTop;
|
||
}
|
||
if (fixedColumnsBodyRight && e.target !== fixedColumnsBodyRight) {
|
||
fixedColumnsBodyRight.scrollTop = e.target.scrollTop;
|
||
}
|
||
if (bodyTable && e.target !== bodyTable) {
|
||
bodyTable.scrollTop = e.target.scrollTop;
|
||
}
|
||
if(this.hoverDom){
|
||
this.hoverDom.style.display = 'none'
|
||
}
|
||
this.lastScrollTop = e.target.scrollTop;
|
||
if(handleScrollY){
|
||
debounce(
|
||
handleScrollY(this.lastScrollTop,this.treeType),
|
||
300)
|
||
}
|
||
|
||
}
|
||
|
||
// Remember last scrollLeft for scroll direction detecting.
|
||
this.lastScrollLeft = e.target.scrollLeft;
|
||
}
|
||
|
||
handleRowHover(isHover, key,event,currentIndex) {
|
||
//增加新的API,设置是否同步Hover状态,提高性能,避免无关的渲染
|
||
let { syncHover,onRowHover,data } = this.props;
|
||
const record = data[currentIndex];
|
||
// 固定列、或者含有hoverdom时情况下同步hover状态
|
||
if(this.columnManager.isAnyColumnsFixed() && syncHover ){
|
||
this.hoverKey = key;
|
||
this.store.setState({
|
||
currentHoverKey: isHover ? key : null,
|
||
});
|
||
}
|
||
if(this.hoverDom){
|
||
if(isHover){
|
||
this.currentHoverKey = key;
|
||
const td = closest(event.target,'td');
|
||
if(td){
|
||
const scrollTop = this.lastScrollTop ?this.lastScrollTop:0
|
||
let top = td.offsetTop - scrollTop;
|
||
if(this.refs.headTable){
|
||
top = top + this.refs.headTable.clientHeight;
|
||
}
|
||
this.hoverDom.style.top = top + 'px';
|
||
this.hoverDom.style.height = td.offsetHeight + 'px';
|
||
this.hoverDom.style.lineHeight = td.offsetHeight + 'px';
|
||
this.hoverDom.style.display = 'block';
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
onRowHover && onRowHover(currentIndex,record);
|
||
|
||
}
|
||
|
||
onRowHoverMouseEnter = () =>{
|
||
|
||
this.store.setState({
|
||
currentHoverKey: this.currentHoverKey,
|
||
});
|
||
this.hoverDom.style.display = 'block';
|
||
|
||
}
|
||
onRowHoverMouseLeave = () =>{
|
||
|
||
}
|
||
onFocus=(e)=>{
|
||
this.props.onKeyTab&&this.props.onKeyTab();
|
||
}
|
||
|
||
onKeyDown=(e)=>{
|
||
let event = Event.getEvent(e);
|
||
// event.preventDefault?event.preventDefault():event.returnValue = false;
|
||
if(event.keyCode === 38){//up
|
||
event.preventDefault&&event.preventDefault();
|
||
this.props.onKeyUp&&this.props.onKeyUp();
|
||
}else if(event.keyCode === 40){//down
|
||
event.preventDefault&&event.preventDefault();
|
||
this.props.onKeyDown&&this.props.onKeyDown();
|
||
}
|
||
this.props.onTableKeyDown&&this.props.onTableKeyDown();
|
||
}
|
||
|
||
render() {
|
||
const props = this.props;
|
||
const clsPrefix = props.clsPrefix;
|
||
const hasFixedLeft = this.columnManager.isAnyColumnsLeftFixed();
|
||
let className = props.clsPrefix;
|
||
if (props.className) {
|
||
className += ` ${props.className}`;
|
||
}
|
||
if (props.useFixedHeader || (props.scroll && props.scroll.y)) {
|
||
className += ` ${clsPrefix}-fixed-header`;
|
||
}
|
||
if (props.bordered) {
|
||
className += ` ${clsPrefix}-bordered`;
|
||
}
|
||
className += ` ${clsPrefix}-scroll-position-${this.state.scrollPosition}`;
|
||
//如果传入height说明是固定高度
|
||
if(props.height){
|
||
className += ' fixed-height';
|
||
}
|
||
if(props.bodyDisplayInRow){
|
||
className += ' body-dispaly-in-row'
|
||
}
|
||
if(props.headerDisplayInRow){
|
||
className += ' header-dispaly-in-row'
|
||
}
|
||
const isTableScroll = this.columnManager.isAnyColumnsFixed() ||
|
||
props.scroll.x ||
|
||
props.scroll.y;
|
||
let loading = props.loading;
|
||
if (typeof loading === 'boolean') {
|
||
loading = {
|
||
show: loading,
|
||
};
|
||
}
|
||
if (props.size) {
|
||
className += ` ${clsPrefix}-${props.size}`;
|
||
}
|
||
if(hasFixedLeft){
|
||
className += ` has-fixed-left`;
|
||
}
|
||
|
||
return (
|
||
<div className={className} style={props.style} ref={el => this.contentTable = el}
|
||
tabIndex={props.focusable && (props.tabIndex?props.tabIndex:'0')} >
|
||
{this.getTitle()}
|
||
<div className={`${clsPrefix}-content`}>
|
||
|
||
<div className={isTableScroll ? `${clsPrefix}-scroll` : ''} >
|
||
{this.getTable({ columns: this.columnManager.groupedColumns() })}
|
||
{this.getEmptyText()}
|
||
{this.getFooter()}
|
||
</div>
|
||
|
||
{hasFixedLeft &&
|
||
<div className={`${clsPrefix}-fixed-left`}>
|
||
{this.getLeftFixedTable()}
|
||
</div>}
|
||
{this.columnManager.isAnyColumnsRightFixed() &&
|
||
<div className={`${clsPrefix}-fixed-right`}>
|
||
{this.getRightFixedTable()}
|
||
</div>}
|
||
</div>
|
||
<Loading
|
||
container={this}
|
||
{...loading} />
|
||
{ props.hoverContent && <div className="u-row-hover"
|
||
onMouseEnter={this.onRowHoverMouseEnter} onMouseLeave={this.onRowHoverMouseLeave} ref={el=> this.hoverDom = el }>{props.hoverContent()}</div>}
|
||
</div>
|
||
);
|
||
}
|
||
};
|
||
|
||
Table.propTypes = propTypes;
|
||
Table.defaultProps = defaultProps;
|
||
|
||
export default Table;
|