Skip to content

Commit

Permalink
fix(Table): support lock columns with colspan, close #1452
Browse files Browse the repository at this point in the history
- add event listener to table body only when crossline is on
- correct colIndex, columns of lock right should not start with 0
  • Loading branch information
youluna committed Jan 12, 2020
1 parent 7e811ed commit 8ae3e21
Show file tree
Hide file tree
Showing 10 changed files with 288 additions and 77 deletions.
87 changes: 87 additions & 0 deletions docs/table/demo/colspan-lock-columns.md
@@ -0,0 +1,87 @@
# 行列合并与锁列

- order: 7

锁列会可能会影响行列合并的 `colIndex``lock='left'`的列会被提升到第0列,多个左锁列按照出现的先后顺序,从0到1标记列索引;
`lock='right'`的列会被提升到最后一列,多个右锁列按照出现顺序,从 `lastIndex - n``lastIndex` 标记列索引。

:::lang=en-us
# Merge cell with lock columns

- order: 7

Merging column through cellProps.
:::

---

````jsx
import { Table, Button } from '@alifd/next';

let columns = new Array(4).fill({
dataIndex: 'data',
title: 'Data',
width: 200,
});
columns.unshift({
dataIndex: 'id',
title: 'Id',
width: 100,
lock: 'left',
});
columns.push({
dataIndex: 'state',
title: 'State',
width: 200,
});
columns.push({
title: 'Action',
width: 100,
align: 'center',
cell: () => <Button>delete</Button>,
lock: 'right'
});

const dataSource = [{
id: 30000,
data: '$13.02',
state: 'normal',
}, {
id: 30001,
data: '$16.02',
state: 'normal',
}, {
id: 30002,
data: '$63.0002',
state: 'error',
}];

ReactDOM.render(
<Table
type="primary"
dataSource={dataSource}
cellProps={(rowIndex, colIndex) => {
if (colIndex === 0) {
return {
colSpan: 1,
rowSpan: 2
};
}
if (colIndex === columns.length - 1) {
return {
colSpan: 1,
rowSpan: 3
};
}
}
}
>
{
columns.map((col, i) => {
return <Table.Column key={i} {...col} />
})
}
</Table>,
mountNode
);
````
94 changes: 51 additions & 43 deletions src/table/base.jsx
Expand Up @@ -281,6 +281,7 @@ export default class Table extends React.Component {
* 在 hover 时出现十字参考轴,适用于表头比较复杂,需要做表头分类的场景。
*/
crossline: PropTypes.bool,
lengths: PropTypes.object,
};

static defaultProps = {
Expand Down Expand Up @@ -446,6 +447,10 @@ export default class Table extends React.Component {
});
});

const { lockType, lengths } = this.props;
const start = lockType === 'right' ? lengths.origin - lengths.right : 0;
this.addColIndex(flatChildren, start);

return {
flatChildren,
groupChildren,
Expand Down Expand Up @@ -624,10 +629,10 @@ export default class Table extends React.Component {
this[cellRef] = cell;
};

handleHoverClass = (rowIndex, colIndex, isAdd) => {
handleColHoverClass = (rowIndex, colIndex, isAdd) => {
const { crossline } = this.props;
const funcName = isAdd ? 'addClass' : 'removeClass';
crossline &&
if (crossline) {
this.props.entireDataSource.forEach((val, index) => {
try {
// in case of finding an unmounted component due to cached data
Expand All @@ -641,72 +646,75 @@ export default class Table extends React.Component {
return null;
}
});
}
};

/**
* @param event
* @returns {Object} { rowIndex: string; colIndex: string }
*/
findEventTarget = e => {
const { prefix } = this.props;
const target = dom.getClosest(e.target, `td.${prefix}table-cell`);
const colIndex = target && target.getAttribute('data-next-table-col');
const rowIndex = target && target.getAttribute('data-next-table-row');

try {
// in case of finding an unmounted component due to cached data
// need to clear refs of this.tableInc when dataSource Changed
// in virtual table
const currentRow = findDOMNode(this.getRowRef(rowIndex));
currentRow && dom[funcName](currentRow, 'hovered');
const currentCol = findDOMNode(this.getCellRef(rowIndex, colIndex));
if (currentCol === target) {
return {
colIndex,
rowIndex,
};
}
} catch (error) {
return null;
return {};
}
};

findEventTarget = e => {
const { crossline } = this.props;
let colIndex = e.target.getAttribute('data-next-table-col'),
rowIndex = e.target.getAttribute('data-next-table-row');
crossline &&
(!colIndex && !rowIndex) &&
this.props.entireDataSource.forEach((val, row) => {
this.flatChildren.forEach((child, col) => {
try {
// in case of finding an unmounted component due to cached data
// need to clear refs of this.tableInc when dataSource Changed
// in virtual table
const currentCol = findDOMNode(
this.getCellRef(row, col)
);
if (currentCol && currentCol.contains(e.target)) {
colIndex = col;
rowIndex = row;
return false;
}
} catch (error) {
return null;
}
});
});

return {
colIndex,
rowIndex,
};
return {};
};

onBodyMouseOver = e => {
const { colIndex, rowIndex } = this.findEventTarget(e);

if (this.colIndex === colIndex && this.rowIndex === rowIndex) {
const { crossline } = this.props;
if (!crossline) {
return;
}
this.handleHoverClass(rowIndex, colIndex, true);

const { colIndex, rowIndex } = this.findEventTarget(e);
// colIndex, rowIndex are string
if (!colIndex || !rowIndex) {
return;
}
this.handleColHoverClass(rowIndex, colIndex, true);
this.colIndex = colIndex;
this.rowIndex = rowIndex;
};

onBodyMouseOut = e => {
this.handleHoverClass(this.rowIndex, this.colIndex, false);
const { crossline } = this.props;
if (!crossline) {
return;
}

const { colIndex, rowIndex } = this.findEventTarget(e);
this.handleHoverClass(rowIndex, colIndex, false);

// colIndex, rowIndex are string
if (!colIndex || !rowIndex) {
return;
}
this.handleColHoverClass(this.rowIndex, this.colIndex, false);
this.colIndex = -1;
this.rowIndex = -1;
};

addColIndex = (children, start = 0) => {
children.forEach((child, i) => {
child.__colIndex = start + i;
});
};

render() {
const ret = this.normalizeChildrenState(this.props);
this.groupChildren = ret.groupChildren;
Expand Down
1 change: 1 addition & 0 deletions src/table/base/body.jsx
Expand Up @@ -158,6 +158,7 @@ export default class Body extends React.Component {
primaryKey={primaryKey}
record={record}
rowIndex={rowIndex}
__rowIndex={rowIndex}
prefix={prefix}
pure={pure}
cellRef={cellRef}
Expand Down
5 changes: 4 additions & 1 deletion src/table/base/cell.jsx
Expand Up @@ -14,6 +14,8 @@ export default class Cell extends React.Component {
isIconLeft: PropTypes.bool,
colIndex: PropTypes.number,
rowIndex: PropTypes.number,
// 经过锁列调整后的列索引,lock right的列会从非0开始
__colIndex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
title: PropTypes.any,
width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
context: PropTypes.any,
Expand Down Expand Up @@ -64,6 +66,7 @@ export default class Cell extends React.Component {
resizable,
colIndex,
rowIndex,
__colIndex,
record,
context,
align,
Expand Down Expand Up @@ -117,7 +120,7 @@ export default class Cell extends React.Component {
<div
className={`${prefix}table-cell-wrapper`}
style={innerStyle}
data-next-table-col={colIndex}
data-next-table-col={__colIndex}
data-next-table-row={rowIndex}
>
{isIconLeft ? children : content}
Expand Down
33 changes: 26 additions & 7 deletions src/table/base/row.jsx
Expand Up @@ -62,15 +62,29 @@ export default class Row extends React.Component {
};

onMouseEnter = e => {
const { record, rowIndex, onMouseEnter } = this.props;
onMouseEnter(record, rowIndex, e);
const { record, rowIndex, __rowIndex } = this.props;
const row = __rowIndex || rowIndex;
this.onRowHover(record, row, true, e);
};

onMouseLeave = e => {
const { record, rowIndex, onMouseLeave } = this.props;
onMouseLeave(record, rowIndex, e);
const { record, rowIndex, __rowIndex } = this.props;
const row = __rowIndex || rowIndex;
this.onRowHover(record, row, false, e);
};

onRowHover(record, index, isEnter, e) {
const { onMouseEnter, onMouseLeave } = this.props,
currentRow = findDOMNode(this);
if (isEnter) {
onMouseEnter(record, index, e);
currentRow && dom.addClass(currentRow, 'hovered');
} else {
onMouseLeave(record, index, e);
currentRow && dom.removeClass(currentRow, 'hovered');
}
}

renderCells(record, rowIndex) {
const {
Cell,
Expand All @@ -79,6 +93,8 @@ export default class Row extends React.Component {
cellRef,
prefix,
primaryKey,
// __rowIndex 是连贯的table行的索引,只有在开启expandedIndexSimulate的ExpandedTable模式下__rowIndex可能会不等于rowIndex
__rowIndex,
pure,
locale,
rtl,
Expand All @@ -88,7 +104,7 @@ export default class Row extends React.Component {
rowIndex = rowIndex !== undefined ? rowIndex : this.props.rowIndex;

const { lockType } = this.context;
return columns.map((child, colIndex) => {
return columns.map((child, index) => {
/* eslint-disable no-unused-vars, prefer-const */
const {
dataIndex,
Expand All @@ -97,8 +113,10 @@ export default class Row extends React.Component {
width,
colSpan,
style,
__colIndex,
...others
} = child;
const colIndex = '__colIndex' in child ? __colIndex : index;
// colSpan should show in body td by the way of <Table.Column colSpan={2} />
// tbody's cell merge should only by the way of <Table cellProps={} />

Expand Down Expand Up @@ -140,12 +158,12 @@ export default class Row extends React.Component {

return (
<Cell
key={colIndex}
key={`${__rowIndex}-${colIndex}`}
{...others}
{...attrs}
data-next-table-col={colIndex}
data-next-table-row={rowIndex}
ref={cell => cellRef(rowIndex, colIndex, cell)}
ref={cell => cellRef(__rowIndex, colIndex, cell)}
prefix={prefix}
pure={pure}
primaryKey={primaryKey}
Expand Down Expand Up @@ -188,6 +206,7 @@ export default class Row extends React.Component {
getCellProps,
rowIndex,
record,
__rowIndex,
children,
primaryKey,
cellRef,
Expand Down
3 changes: 3 additions & 0 deletions src/table/expanded.jsx
Expand Up @@ -216,6 +216,7 @@ export default function expanded(BaseComponent) {
hasExpandedRowCtrl,
children,
dataSource,
entireDataSource,
getExpandedColProps,
expandedRowIndent,
onRowOpen,
Expand All @@ -226,6 +227,7 @@ export default function expanded(BaseComponent) {
components = { ...components };
components.Row = RowComponent;
dataSource = this.normalizeDataSource(dataSource);
entireDataSource = this.normalizeDataSource(entireDataSource);
}
if (expandedRowRender && hasExpandedRowCtrl) {
children = this.normalizeChildren(children);
Expand All @@ -235,6 +237,7 @@ export default function expanded(BaseComponent) {
<BaseComponent
{...others}
dataSource={dataSource}
entireDataSource={entireDataSource}
components={components}
>
{children}
Expand Down

0 comments on commit 8ae3e21

Please sign in to comment.