312 lines
7.8 KiB
Vue
312 lines
7.8 KiB
Vue
import classNames from 'classnames';
|
|
import PropTypes from '../../_util/vue-types';
|
|
import { connect } from '../../_util/store';
|
|
import TableCell from './TableCell';
|
|
import { initDefaultProps, mergeProps, getStyle } from '../../_util/props-util';
|
|
import BaseMixin from '../../_util/BaseMixin';
|
|
import warning from '../../_util/warning';
|
|
function noop() {}
|
|
const TableRow = {
|
|
name: 'TableRow',
|
|
mixins: [BaseMixin],
|
|
props: initDefaultProps(
|
|
{
|
|
customRow: PropTypes.func,
|
|
// onRowClick: PropTypes.func,
|
|
// onRowDoubleClick: PropTypes.func,
|
|
// onRowContextMenu: PropTypes.func,
|
|
// onRowMouseEnter: PropTypes.func,
|
|
// onRowMouseLeave: PropTypes.func,
|
|
record: PropTypes.object,
|
|
prefixCls: PropTypes.string,
|
|
// onHover: PropTypes.func,
|
|
columns: PropTypes.array,
|
|
height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
index: PropTypes.number,
|
|
rowKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
|
className: PropTypes.string,
|
|
indent: PropTypes.number,
|
|
indentSize: PropTypes.number,
|
|
hasExpandIcon: PropTypes.func,
|
|
hovered: PropTypes.bool.isRequired,
|
|
visible: PropTypes.bool.isRequired,
|
|
store: PropTypes.object.isRequired,
|
|
fixed: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
|
|
renderExpandIcon: PropTypes.func,
|
|
renderExpandIconCell: PropTypes.func,
|
|
components: PropTypes.any,
|
|
expandedRow: PropTypes.bool,
|
|
isAnyColumnsFixed: PropTypes.bool,
|
|
ancestorKeys: PropTypes.array.isRequired,
|
|
expandIconColumnIndex: PropTypes.number,
|
|
expandRowByClick: PropTypes.bool,
|
|
// visible: PropTypes.bool,
|
|
// hovered: PropTypes.bool,
|
|
// height: PropTypes.any,
|
|
},
|
|
{
|
|
// expandIconColumnIndex: 0,
|
|
// expandRowByClick: false,
|
|
hasExpandIcon() {},
|
|
renderExpandIcon() {},
|
|
renderExpandIconCell() {},
|
|
},
|
|
),
|
|
|
|
data() {
|
|
// this.shouldRender = this.visible
|
|
return {
|
|
shouldRender: this.visible,
|
|
};
|
|
},
|
|
|
|
mounted() {
|
|
if (this.shouldRender) {
|
|
this.$nextTick(() => {
|
|
this.saveRowRef();
|
|
});
|
|
}
|
|
},
|
|
watch: {
|
|
visible(val) {
|
|
if (val) {
|
|
this.shouldRender = true;
|
|
}
|
|
},
|
|
},
|
|
|
|
updated() {
|
|
if (this.shouldRender && !this.rowRef) {
|
|
this.$nextTick(() => {
|
|
this.saveRowRef();
|
|
});
|
|
}
|
|
},
|
|
methods: {
|
|
onRowClick(event, rowPropFunc = noop) {
|
|
const { record, index } = this;
|
|
this.__emit('rowClick', record, index, event);
|
|
rowPropFunc(event);
|
|
},
|
|
|
|
onRowDoubleClick(event, rowPropFunc = noop) {
|
|
const { record, index } = this;
|
|
this.__emit('rowDoubleClick', record, index, event);
|
|
rowPropFunc(event);
|
|
},
|
|
|
|
onContextMenu(event, rowPropFunc = noop) {
|
|
const { record, index } = this;
|
|
this.__emit('rowContextmenu', record, index, event);
|
|
rowPropFunc(event);
|
|
},
|
|
|
|
onMouseEnter(event, rowPropFunc = noop) {
|
|
const { record, index, rowKey } = this;
|
|
this.__emit('hover', true, rowKey);
|
|
this.__emit('rowMouseenter', record, index, event);
|
|
rowPropFunc(event);
|
|
},
|
|
|
|
onMouseLeave(event, rowPropFunc = noop) {
|
|
const { record, index, rowKey } = this;
|
|
this.__emit('hover', false, rowKey);
|
|
this.__emit('rowMouseleave', record, index, event);
|
|
rowPropFunc(event);
|
|
},
|
|
|
|
setExpandedRowHeight() {
|
|
const { store, rowKey } = this;
|
|
let { expandedRowsHeight } = store.getState();
|
|
const height = this.rowRef.getBoundingClientRect().height;
|
|
expandedRowsHeight = {
|
|
...expandedRowsHeight,
|
|
[rowKey]: height,
|
|
};
|
|
store.setState({ expandedRowsHeight });
|
|
},
|
|
|
|
setRowHeight() {
|
|
const { store, rowKey } = this;
|
|
const { fixedColumnsBodyRowsHeight } = store.getState();
|
|
const height = this.rowRef.getBoundingClientRect().height;
|
|
store.setState({
|
|
fixedColumnsBodyRowsHeight: {
|
|
...fixedColumnsBodyRowsHeight,
|
|
[rowKey]: height,
|
|
},
|
|
});
|
|
},
|
|
|
|
getStyle() {
|
|
const { height, visible } = this;
|
|
let style = getStyle(this);
|
|
if (height) {
|
|
style = { ...style, height };
|
|
}
|
|
|
|
if (!visible && !style.display) {
|
|
style = { ...style, display: 'none' };
|
|
}
|
|
|
|
return style;
|
|
},
|
|
|
|
saveRowRef() {
|
|
this.rowRef = this.$el;
|
|
|
|
const { isAnyColumnsFixed, fixed, expandedRow, ancestorKeys } = this;
|
|
|
|
if (!isAnyColumnsFixed) {
|
|
return;
|
|
}
|
|
|
|
if (!fixed && expandedRow) {
|
|
this.setExpandedRowHeight();
|
|
}
|
|
|
|
if (!fixed && ancestorKeys.length >= 0) {
|
|
this.setRowHeight();
|
|
}
|
|
},
|
|
},
|
|
|
|
render() {
|
|
if (!this.shouldRender) {
|
|
return null;
|
|
}
|
|
|
|
const {
|
|
prefixCls,
|
|
columns,
|
|
record,
|
|
rowKey,
|
|
index,
|
|
customRow = noop,
|
|
indent,
|
|
indentSize,
|
|
hovered,
|
|
height,
|
|
visible,
|
|
components,
|
|
hasExpandIcon,
|
|
renderExpandIcon,
|
|
renderExpandIconCell,
|
|
} = this;
|
|
const BodyRow = components.body.row;
|
|
const BodyCell = components.body.cell;
|
|
|
|
let className = '';
|
|
|
|
if (hovered) {
|
|
className += ` ${prefixCls}-hover`;
|
|
}
|
|
|
|
const cells = [];
|
|
|
|
renderExpandIconCell(cells);
|
|
|
|
for (let i = 0; i < columns.length; i += 1) {
|
|
const column = columns[i];
|
|
|
|
warning(
|
|
column.onCellClick === undefined,
|
|
'column[onCellClick] is deprecated, please use column[customCell] instead.',
|
|
);
|
|
|
|
cells.push(
|
|
<TableCell
|
|
prefixCls={prefixCls}
|
|
record={record}
|
|
indentSize={indentSize}
|
|
indent={indent}
|
|
index={index}
|
|
column={column}
|
|
key={column.key || column.dataIndex}
|
|
expandIcon={hasExpandIcon(i) && renderExpandIcon()}
|
|
component={BodyCell}
|
|
/>,
|
|
);
|
|
}
|
|
|
|
const { class: customClass, className: customClassName, style: customStyle, ...rowProps } =
|
|
customRow(record, index) || {};
|
|
|
|
let style = { height: typeof height === 'number' ? `${height}px` : height };
|
|
|
|
if (!visible) {
|
|
style.display = 'none';
|
|
}
|
|
|
|
style = { ...style, ...customStyle };
|
|
const rowClassName = classNames(
|
|
prefixCls,
|
|
className,
|
|
`${prefixCls}-level-${indent}`,
|
|
customClassName,
|
|
customClass,
|
|
);
|
|
const rowPropEvents = rowProps.on || {};
|
|
const bodyRowProps = mergeProps(
|
|
{ ...rowProps, style },
|
|
{
|
|
on: {
|
|
click: e => {
|
|
this.onRowClick(e, rowPropEvents.click);
|
|
},
|
|
dblclick: e => {
|
|
this.onRowDoubleClick(e, rowPropEvents.dblclick);
|
|
},
|
|
mouseenter: e => {
|
|
this.onMouseEnter(e, rowPropEvents.mouseenter);
|
|
},
|
|
mouseleave: e => {
|
|
this.onMouseLeave(e, rowPropEvents.mouseleave);
|
|
},
|
|
contextmenu: e => {
|
|
this.onContextMenu(e, rowPropEvents.contextmenu);
|
|
},
|
|
},
|
|
class: rowClassName,
|
|
},
|
|
{
|
|
attrs: {
|
|
'data-row-key': rowKey,
|
|
},
|
|
},
|
|
);
|
|
return <BodyRow {...bodyRowProps}>{cells}</BodyRow>;
|
|
},
|
|
};
|
|
|
|
function getRowHeight(state, props) {
|
|
const { expandedRowsHeight, fixedColumnsBodyRowsHeight } = state;
|
|
const { fixed, rowKey } = props;
|
|
|
|
if (!fixed) {
|
|
return null;
|
|
}
|
|
|
|
if (expandedRowsHeight[rowKey]) {
|
|
return expandedRowsHeight[rowKey];
|
|
}
|
|
|
|
if (fixedColumnsBodyRowsHeight[rowKey]) {
|
|
return fixedColumnsBodyRowsHeight[rowKey];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
export default connect((state, props) => {
|
|
const { currentHoverKey, expandedRowKeys } = state;
|
|
const { rowKey, ancestorKeys } = props;
|
|
const visible = ancestorKeys.length === 0 || ancestorKeys.every(k => expandedRowKeys.includes(k));
|
|
|
|
return {
|
|
visible,
|
|
hovered: currentHoverKey === rowKey,
|
|
height: getRowHeight(state, props),
|
|
};
|
|
})(TableRow);
|