add vc-table
parent
e968570d6f
commit
02028e7749
|
@ -0,0 +1,59 @@
|
|||
|
||||
.move-enter, .move-appear {
|
||||
opacity: 0;
|
||||
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
animation-duration: 2.5s;
|
||||
animation-fill-mode: both;
|
||||
animation-play-state: paused;
|
||||
}
|
||||
|
||||
.move-leave {
|
||||
animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||
animation-duration: .5s;
|
||||
animation-fill-mode: both;
|
||||
animation-play-state: paused;
|
||||
}
|
||||
|
||||
.move-enter.move-enter-active, .move-appear.move-enter-active {
|
||||
animation-name: moveLeftIn;
|
||||
animation-play-state: running;
|
||||
}
|
||||
|
||||
.move-leave.move-leave-active {
|
||||
animation-name: moveRightOut;
|
||||
animation-play-state: running;
|
||||
}
|
||||
|
||||
@keyframes moveLeftIn {
|
||||
0% {
|
||||
transform-origin: 0 0;
|
||||
transform: translateX(30px);
|
||||
opacity: 0;
|
||||
background: #fff6de;
|
||||
}
|
||||
20% {
|
||||
transform-origin: 0 0;
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
80%{
|
||||
background: #fff6de;
|
||||
}
|
||||
100%{
|
||||
background: transparent;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes moveRightOut {
|
||||
0% {
|
||||
transform-origin: 0 0;
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform-origin: 0 0;
|
||||
transform: translateX(-30px);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
@tablePrefixCls: rc-table;
|
||||
@table-border-color: #e9e9e9;
|
||||
|
||||
.@{tablePrefixCls}.bordered {
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
th, td {
|
||||
border: 1px solid @table-border-color;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,225 @@
|
|||
@tablePrefixCls: rc-table;
|
||||
@text-color : #666;
|
||||
@font-size-base : 12px;
|
||||
@line-height: 1.5;
|
||||
@table-border-color: #e9e9e9;
|
||||
@table-head-background-color: #f7f7f7;
|
||||
@vertical-padding: 16px;
|
||||
@horizontal-padding: 8px;
|
||||
|
||||
.@{tablePrefixCls} {
|
||||
font-size: @font-size-base;
|
||||
color: @text-color;
|
||||
transition: opacity 0.3s ease;
|
||||
position: relative;
|
||||
line-height: @line-height;
|
||||
overflow: hidden;
|
||||
|
||||
.@{tablePrefixCls}-scroll {
|
||||
overflow: auto;
|
||||
table {
|
||||
width: auto;
|
||||
min-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.@{tablePrefixCls}-header {
|
||||
overflow: hidden;
|
||||
background: @table-head-background-color;
|
||||
}
|
||||
|
||||
&-fixed-header &-body {
|
||||
background: #fff;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&-fixed-header &-body-inner {
|
||||
height: 100%;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
&-fixed-header &-scroll &-header {
|
||||
overflow-x: scroll;
|
||||
padding-bottom: 20px;
|
||||
margin-bottom: -20px;
|
||||
overflow-y: scroll;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.@{tablePrefixCls}-title {
|
||||
padding: @vertical-padding @horizontal-padding;
|
||||
border-top: 1px solid @table-border-color;
|
||||
}
|
||||
|
||||
.@{tablePrefixCls}-content {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.@{tablePrefixCls}-footer {
|
||||
padding: @vertical-padding @horizontal-padding;
|
||||
border-bottom: 1px solid @table-border-color;
|
||||
}
|
||||
|
||||
.@{tablePrefixCls}-placeholder {
|
||||
padding: 16px 8px;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid @table-border-color;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
&-fixed-columns {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
background: transparent;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: separate;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
background: @table-head-background-color;
|
||||
font-weight: bold;
|
||||
transition: background .3s ease;
|
||||
}
|
||||
|
||||
td {
|
||||
border-bottom: 1px solid @table-border-color;
|
||||
&:empty:after {
|
||||
content: '.'; // empty cell placeholder
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
tr {
|
||||
transition: all .3s ease;
|
||||
&:hover {
|
||||
background: #eaf8fe;
|
||||
}
|
||||
&.@{tablePrefixCls}-row-hover {
|
||||
background: #eaf8fe;
|
||||
}
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: @vertical-padding @horizontal-padding;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.@{tablePrefixCls} {
|
||||
&-expand-icon-col {
|
||||
width: 34px;
|
||||
}
|
||||
&-row, &-expanded-row {
|
||||
&-expand-icon {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
text-align: center;
|
||||
line-height: 16px;
|
||||
border: 1px solid @table-border-color;
|
||||
user-select: none;
|
||||
background: #fff;
|
||||
}
|
||||
&-spaced {
|
||||
visibility: hidden;
|
||||
}
|
||||
&-spaced:after {
|
||||
content: '.'
|
||||
}
|
||||
|
||||
&-expanded:after {
|
||||
content: '-'
|
||||
}
|
||||
|
||||
&-collapsed:after {
|
||||
content: '+'
|
||||
}
|
||||
}
|
||||
tr&-expanded-row {
|
||||
background: #f7f7f7;
|
||||
&:hover {
|
||||
background: #f7f7f7;
|
||||
}
|
||||
}
|
||||
&-column-hidden {
|
||||
display: none;
|
||||
}
|
||||
&-prev-columns-page,
|
||||
&-next-columns-page {
|
||||
cursor: pointer;
|
||||
color: #666;
|
||||
z-index: 1;
|
||||
&:hover {
|
||||
color: #2db7f5;
|
||||
}
|
||||
&-disabled {
|
||||
cursor: not-allowed;
|
||||
color: #999;
|
||||
&:hover {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
&-prev-columns-page {
|
||||
margin-right: 8px;
|
||||
&:before {
|
||||
content: '<';
|
||||
}
|
||||
}
|
||||
&-next-columns-page {
|
||||
float: right;
|
||||
&:before {
|
||||
content: '>';
|
||||
}
|
||||
}
|
||||
|
||||
&-fixed-left,
|
||||
&-fixed-right {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
overflow: hidden;
|
||||
table {
|
||||
width: auto;
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&-fixed-left {
|
||||
left: 0;
|
||||
box-shadow: 4px 0 4px rgba(100, 100, 100, 0.1);
|
||||
& .@{tablePrefixCls}-body-inner {
|
||||
margin-right: -20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
.@{tablePrefixCls}-fixed-header & .@{tablePrefixCls}-body-inner {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&-fixed-right {
|
||||
right: 0;
|
||||
box-shadow: -4px 0 4px rgba(100, 100, 100, 0.1);
|
||||
|
||||
// hide expand row content in right fixed Table
|
||||
// https://github.com/ant-design/ant-design/issues/1898
|
||||
.@{tablePrefixCls}-expanded-row {
|
||||
color: transparent;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
&&-scroll-position-left &-fixed-left {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&&-scroll-position-right &-fixed-right {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import Animate from 'rc-animate';
|
||||
import 'rc-table/assets/index.less';
|
||||
import 'rc-table/assets/animation.less';
|
||||
|
||||
const AnimateBody = (props) =>
|
||||
<Animate transitionName="move" component="tbody" {...props} />;
|
||||
|
||||
class Demo extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.columns = [
|
||||
{ title: 'title1', dataIndex: 'a', key: 'a', width: 100 },
|
||||
{ id: '123', title: 'title2', dataIndex: 'b', key: 'b', width: 100 },
|
||||
{ title: 'title3', dataIndex: 'c', key: 'c', width: 200 },
|
||||
{
|
||||
title: 'Operations', dataIndex: '', key: 'd', render: (text, record) =>
|
||||
<a onClick={e => this.onDelete(record.key, e)} href="#">Delete</a>,
|
||||
},
|
||||
];
|
||||
this.state = {
|
||||
data: [
|
||||
{ a: '123', key: '1' },
|
||||
{ a: 'cdd', b: 'edd', key: '2' },
|
||||
{ a: '1333', c: 'eee', key: '3' },
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
onDelete(key, e) {
|
||||
console.log('Delete', key);
|
||||
e.preventDefault();
|
||||
const data = this.state.data.filter(item => item.key !== key);
|
||||
this.setState({ data });
|
||||
}
|
||||
|
||||
onAdd() {
|
||||
const data = [...this.state.data];
|
||||
data.push({
|
||||
a: 'new data',
|
||||
b: 'new data',
|
||||
c: 'new data',
|
||||
key: Date.now(),
|
||||
});
|
||||
this.setState({ data });
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{ margin: 20 }}>
|
||||
<h2>Table row with animation</h2>
|
||||
<button onClick={() => this.onAdd()}>添加</button>
|
||||
<Table
|
||||
columns={this.columns}
|
||||
data={this.state.data}
|
||||
components={{
|
||||
body: { wrapper: AnimateBody },
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
ReactDOM.render(
|
||||
<Demo />,
|
||||
document.getElementById('__react-content')
|
||||
);
|
|
@ -0,0 +1,87 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const columns = [{
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
width: 400,
|
||||
}, {
|
||||
title: 'Age',
|
||||
dataIndex: 'age',
|
||||
key: 'age',
|
||||
width: 100,
|
||||
}, {
|
||||
title: 'Address',
|
||||
dataIndex: 'address',
|
||||
key: 'address',
|
||||
width: 200,
|
||||
}, {
|
||||
title: 'Operations',
|
||||
dataIndex: 'operation',
|
||||
key: 'x',
|
||||
width: 150,
|
||||
}];
|
||||
|
||||
const data = [{
|
||||
key: 1,
|
||||
name: 'a',
|
||||
age: 32,
|
||||
address: 'I am a',
|
||||
children: [{
|
||||
key: 11,
|
||||
name: 'aa',
|
||||
age: 33,
|
||||
address: 'I am aa',
|
||||
}, {
|
||||
key: 12,
|
||||
name: 'ab',
|
||||
age: 33,
|
||||
address: 'I am ab',
|
||||
children: [{
|
||||
key: 121,
|
||||
name: 'aba',
|
||||
age: 33,
|
||||
address: 'I am aba',
|
||||
}],
|
||||
}, {
|
||||
key: 13,
|
||||
name: 'ac',
|
||||
age: 33,
|
||||
address: 'I am ac',
|
||||
children: [{
|
||||
key: 131,
|
||||
name: 'aca',
|
||||
age: 33,
|
||||
address: 'I am aca',
|
||||
children: [{
|
||||
key: 1311,
|
||||
name: 'acaa',
|
||||
age: 33,
|
||||
address: 'I am acaa',
|
||||
}, {
|
||||
key: 1312,
|
||||
name: 'acab',
|
||||
age: 33,
|
||||
address: 'I am acab',
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
}, {
|
||||
key: 2,
|
||||
name: 'b',
|
||||
age: 32,
|
||||
address: 'I am b',
|
||||
}];
|
||||
|
||||
function onExpand(expanded, record) {
|
||||
console.log('onExpand', expanded, record);
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<Table defaultExpandAllRows columns={columns} data={data} indentSize={30} onExpand={onExpand} />,
|
||||
document.getElementById('__react-content')
|
||||
);
|
|
@ -0,0 +1,45 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const columns = [
|
||||
{ title: 'title1', dataIndex: 'a',
|
||||
className: 'a',
|
||||
key: 'a', width: 100 },
|
||||
{ id: '123', title: 'title2', dataIndex: 'b',
|
||||
className: 'b',
|
||||
key: 'b', width: 100 },
|
||||
{ title: 'title3', dataIndex: 'c',
|
||||
className: 'c',
|
||||
key: 'c', width: 200 },
|
||||
{
|
||||
title: 'Operations', dataIndex: '',
|
||||
className: 'd',
|
||||
key: 'd', render() {
|
||||
return <a href="#">Operations</a>;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const data = [
|
||||
{ a: '123', key: '1' },
|
||||
{ a: 'cdd', b: 'edd', key: '2' },
|
||||
{ a: '1333', c: 'eee', d: 2, key: '3' },
|
||||
];
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<h2>rowClassName and className</h2>
|
||||
<Table
|
||||
columns={columns}
|
||||
rowClassName={(record, i) => `row-${i}`}
|
||||
expandedRowRender={record => <p>extra: {record.a}</p>}
|
||||
expandedRowClassName={(record, i) => `ex-row-${i}`}
|
||||
data={data}
|
||||
className="table"
|
||||
/>
|
||||
</div>,
|
||||
document.getElementById('__react-content')
|
||||
);
|
|
@ -0,0 +1,107 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const columns = [
|
||||
{ title: '手机号', dataIndex: 'a', colSpan: 2, width: 100, key: 'a', render(o, row, index) {
|
||||
const obj = {
|
||||
children: o,
|
||||
props: {},
|
||||
};
|
||||
// 设置第一行为链接
|
||||
if (index === 0) {
|
||||
obj.children = <a href="#">{o}</a>;
|
||||
}
|
||||
// 第5行合并两列
|
||||
if (index === 4) {
|
||||
obj.props.colSpan = 2;
|
||||
}
|
||||
|
||||
if (index === 5) {
|
||||
obj.props.colSpan = 6;
|
||||
}
|
||||
return obj;
|
||||
} },
|
||||
{ title: '电话', dataIndex: 'b', colSpan: 0, width: 100, key: 'b', render(o, row, index) {
|
||||
const obj = {
|
||||
children: o,
|
||||
props: {},
|
||||
};
|
||||
// 列合并掉的表格设置colSpan=0,不会去渲染
|
||||
if (index === 4 || index === 5) {
|
||||
obj.props.colSpan = 0;
|
||||
}
|
||||
return obj;
|
||||
} },
|
||||
{ title: 'Name', dataIndex: 'c', width: 100, key: 'c', render(o, row, index) {
|
||||
const obj = {
|
||||
children: o,
|
||||
props: {},
|
||||
};
|
||||
|
||||
if (index === 5) {
|
||||
obj.props.colSpan = 0;
|
||||
}
|
||||
return obj;
|
||||
} },
|
||||
{ title: 'Address', dataIndex: 'd', width: 200, key: 'd', render(o, row, index) {
|
||||
const obj = {
|
||||
children: o,
|
||||
props: {},
|
||||
};
|
||||
if (index === 0) {
|
||||
obj.props.rowSpan = 2;
|
||||
}
|
||||
if (index === 1 || index === 5) {
|
||||
obj.props.rowSpan = 0;
|
||||
}
|
||||
|
||||
return obj;
|
||||
} },
|
||||
{ title: 'Gender', dataIndex: 'e', width: 200, key: 'e', render(o, row, index) {
|
||||
const obj = {
|
||||
children: o,
|
||||
props: {},
|
||||
};
|
||||
if (index === 5) {
|
||||
obj.props.colSpan = 0;
|
||||
}
|
||||
return obj;
|
||||
} },
|
||||
{
|
||||
title: 'Operations', dataIndex: '', key: 'f',
|
||||
render(o, row, index) {
|
||||
if (index === 5) {
|
||||
return {
|
||||
props: {
|
||||
colSpan: 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
return <a href="#">Operations</a>;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const data = [
|
||||
{ a: '13812340987', b: '0571-12345678', c: '张三', d: '文一西路', e: 'Male', key: '1' },
|
||||
{ a: '13812340986', b: '0571-98787658', c: '张夫人', d: '文一西路', e: 'Female', key: '2' },
|
||||
{ a: '13812988888', b: '0571-099877', c: '李四', d: '文二西路', e: 'Male', key: '3' },
|
||||
{ a: '1381200008888', b: '0571-099877', c: '王五', d: '文二西路', e: 'Male', key: '4' },
|
||||
{ a: '0571-88888110', c: '李警官', d: '武林门', e: 'Male', key: '5' },
|
||||
{ a: '资料统计完毕于xxxx年xxx月xxx日', key: '6' },
|
||||
];
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<h2>colSpan & rowSpan</h2>
|
||||
<Table
|
||||
columns={columns}
|
||||
data={data}
|
||||
className="table"
|
||||
/>
|
||||
</div>,
|
||||
document.getElementById('__react-content')
|
||||
);
|
|
@ -0,0 +1,84 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
import { Resizable } from 'react-resizable';
|
||||
import 'react-resizable/css/styles.css';
|
||||
|
||||
const ResizeableTitle = (props) => {
|
||||
const { onResize, width, ...restProps } = props;
|
||||
|
||||
if (!width) {
|
||||
return <th {...restProps} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Resizable width={width} height={0} onResize={onResize}>
|
||||
<th {...restProps} />
|
||||
</Resizable>
|
||||
);
|
||||
};
|
||||
|
||||
ResizeableTitle.propTypes = {
|
||||
onResize: PropTypes.func.isRequired,
|
||||
width: PropTypes.number,
|
||||
};
|
||||
|
||||
class Demo extends React.Component {
|
||||
state = {
|
||||
columns: [
|
||||
{ title: 'title1', dataIndex: 'a', key: 'a', width: 100 },
|
||||
{ id: '123', title: 'title2', dataIndex: 'b', key: 'b', width: 100 },
|
||||
{ title: 'title3', dataIndex: 'c', key: 'c', width: 200 },
|
||||
{
|
||||
title: 'Operations', dataIndex: '', key: 'd', render() {
|
||||
return <a href="#">Operations</a>;
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
components = {
|
||||
header: {
|
||||
cell: ResizeableTitle,
|
||||
},
|
||||
}
|
||||
|
||||
data = [
|
||||
{ a: '123', key: '1' },
|
||||
{ a: 'cdd', b: 'edd', key: '2' },
|
||||
{ a: '1333', c: 'eee', d: 2, key: '3' },
|
||||
]
|
||||
|
||||
handleResize = index => (e, { size }) => {
|
||||
this.setState(({ columns }) => {
|
||||
const nextColumns = [...columns];
|
||||
nextColumns[index] = {
|
||||
...nextColumns[index],
|
||||
width: size.width,
|
||||
};
|
||||
return { columns: nextColumns };
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const columns = this.state.columns.map((col, index) => ({
|
||||
...col,
|
||||
onHeaderCell: (column) => ({
|
||||
width: column.width,
|
||||
onResize: this.handleResize(index),
|
||||
}),
|
||||
}));
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>Integrate with react-resizable</h2>
|
||||
<Table components={this.components} columns={columns} data={this.data} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<Demo />, document.getElementById('__react-content'));
|
|
@ -0,0 +1,111 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import Menu, { Item, Divider } from 'rc-menu';
|
||||
import DropDown from 'rc-dropdown';
|
||||
import 'rc-table/assets/index.less';
|
||||
import 'rc-dropdown/assets/index.css';
|
||||
import 'rc-menu/assets/index.css';
|
||||
|
||||
const data = [];
|
||||
for (let i = 0; i < 10; i++) {
|
||||
data.push({
|
||||
key: i,
|
||||
a: `a${i}`,
|
||||
b: `b${i}`,
|
||||
c: `c${i}`,
|
||||
});
|
||||
}
|
||||
|
||||
class Demo extends React.Component {
|
||||
state = {
|
||||
visible: false,
|
||||
}
|
||||
|
||||
filters = []
|
||||
|
||||
handleVisibleChange = (visible) => {
|
||||
this.setState({ visible });
|
||||
}
|
||||
|
||||
handleSelect = (selected) => {
|
||||
this.filters.push(selected);
|
||||
}
|
||||
|
||||
handleDeselect = (key) => {
|
||||
const index = this.filters.indexOf(key);
|
||||
if (index !== -1) {
|
||||
this.filters.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
confirmFilter = () => {
|
||||
console.log(this.filters.join(','));
|
||||
this.setState({
|
||||
visible: false,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const menu = (
|
||||
<Menu
|
||||
style={{ width: 200 }}
|
||||
multiple
|
||||
onSelect={this.handleSelect}
|
||||
onDeselect={this.handleDeselect}
|
||||
>
|
||||
<Item key="1">one</Item>
|
||||
<Item key="2">two</Item>
|
||||
<Item key="3">three</Item>
|
||||
<Divider />
|
||||
<Item disabled>
|
||||
<button
|
||||
style={{
|
||||
cursor: 'pointer',
|
||||
color: '#000',
|
||||
pointerEvents: 'visible',
|
||||
}}
|
||||
onClick={this.confirmFilter}
|
||||
>确定</button>
|
||||
</Item>
|
||||
</Menu>
|
||||
);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: (
|
||||
<div>
|
||||
title1
|
||||
<DropDown
|
||||
trigger={['click']}
|
||||
onVisibleChange={this.handleVisibleChange}
|
||||
visible={this.state.visible}
|
||||
overlay={menu}
|
||||
>
|
||||
<a href="#">filter</a>
|
||||
</DropDown>
|
||||
</div>
|
||||
), key: 'a', dataIndex: 'a', width: 100,
|
||||
},
|
||||
{ title: 'title2', key: 'b', dataIndex: 'b', width: 100 },
|
||||
{ title: 'title3', key: 'c', dataIndex: 'c', width: 200 },
|
||||
];
|
||||
|
||||
return (
|
||||
<Table
|
||||
columns={columns}
|
||||
data={data}
|
||||
rowKey={record => record.key}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<h2>use dropdown</h2>
|
||||
<Demo />
|
||||
</div>,
|
||||
document.getElementById('__react-content')
|
||||
);
|
|
@ -0,0 +1,114 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const tableData = [
|
||||
{ key: 0, a: '123' },
|
||||
{ key: 1, a: 'cdd', b: 'edd' },
|
||||
{ key: 2, a: '1333', c: 'eee', d: 2 },
|
||||
];
|
||||
|
||||
class Demo extends React.Component {
|
||||
state = {
|
||||
data: tableData,
|
||||
expandedRowKeys: [],
|
||||
expandIconAsCell: true,
|
||||
expandRowByClick: false,
|
||||
}
|
||||
|
||||
onExpand = (expanded, record) => {
|
||||
console.log('onExpand', expanded, record);
|
||||
}
|
||||
|
||||
onExpandedRowsChange = (rows) => {
|
||||
this.setState({
|
||||
expandedRowKeys: rows,
|
||||
});
|
||||
}
|
||||
|
||||
onExpandIconAsCellChange = (e) => {
|
||||
this.setState({
|
||||
expandIconAsCell: e.target.checked,
|
||||
});
|
||||
}
|
||||
|
||||
onExpandRowByClickChange = (e) => {
|
||||
this.setState({
|
||||
expandRowByClick: e.target.checked,
|
||||
});
|
||||
}
|
||||
|
||||
columns = [
|
||||
{ title: 'title 1', dataIndex: 'a', key: 'a', width: 100 },
|
||||
{ title: 'title 2', dataIndex: 'b', key: 'b', width: 100 },
|
||||
{ title: 'title 3', dataIndex: 'c', key: 'c', width: 200 },
|
||||
{ title: 'Operation', dataIndex: '', key: 'x', render: this.renderAction },
|
||||
]
|
||||
|
||||
toggleButton() {
|
||||
if (this.state.expandedRowKeys.length) {
|
||||
const closeAll = () => this.setState({ expandedRowKeys: [] });
|
||||
return <button onClick={closeAll}>Close All</button>;
|
||||
}
|
||||
const openAll = () => this.setState({ expandedRowKeys: [0, 1, 2] });
|
||||
return <button onClick={openAll}>Expand All</button>;
|
||||
}
|
||||
|
||||
remove(index) {
|
||||
const data = this.state.data;
|
||||
data.splice(index, 1);
|
||||
this.setState({ data });
|
||||
}
|
||||
|
||||
expandedRowRender(record) {
|
||||
// console.log(record);
|
||||
return <p>extra: {record.a}</p>;
|
||||
}
|
||||
|
||||
renderAction(o, row, index) {
|
||||
return <a href="#" onClick={() => this.remove(index)}>Delete</a>;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { expandIconAsCell, expandRowByClick, expandedRowKeys, data } = this.state;
|
||||
return (
|
||||
<div>
|
||||
{this.toggleButton()}
|
||||
<span style={{ display: 'inline-block', width: 20 }} />
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={expandIconAsCell}
|
||||
onChange={this.onExpandIconAsCellChange}
|
||||
/>
|
||||
expandIconAsCell
|
||||
<span style={{ display: 'inline-block', width: 20 }} />
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={expandRowByClick}
|
||||
onChange={this.onExpandRowByClickChange}
|
||||
/>
|
||||
expandRowByClick
|
||||
<Table
|
||||
columns={this.columns}
|
||||
expandIconAsCell={expandIconAsCell}
|
||||
expandRowByClick={expandRowByClick}
|
||||
expandedRowRender={this.expandedRowRender}
|
||||
expandedRowKeys={expandedRowKeys}
|
||||
onExpandedRowsChange={this.onExpandedRowsChange}
|
||||
onExpand={this.onExpand}
|
||||
data={data}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<h2>expandedRowRender</h2>
|
||||
<Demo />
|
||||
</div>,
|
||||
document.getElementById('__react-content')
|
||||
);
|
|
@ -0,0 +1,46 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const columns = [
|
||||
{ title: 'title1', dataIndex: 'a', key: 'a', width: 100, fixed: 'left' },
|
||||
{ title: 'title2', dataIndex: 'b', key: 'b', width: 100, fixed: 'left' },
|
||||
{ title: 'title3', dataIndex: 'c', key: 'c' },
|
||||
{ title: 'title4', dataIndex: 'b', key: 'd' },
|
||||
{ title: 'title5', dataIndex: 'b', key: 'e' },
|
||||
{ title: 'title6', dataIndex: 'b', key: 'f',
|
||||
render: () => <div style={{ height: '40px', lineHeight: '40px' }}>我很高</div> },
|
||||
{ title: 'title7', dataIndex: 'b', key: 'g' },
|
||||
{ title: 'title8', dataIndex: 'b', key: 'h' },
|
||||
{ title: 'title9', dataIndex: 'b', key: 'i' },
|
||||
{ title: 'title10', dataIndex: 'b', key: 'j' },
|
||||
{ title: 'title11', dataIndex: 'b', key: 'k' },
|
||||
{ title: 'title12', dataIndex: 'b', key: 'l', width: 100, fixed: 'right' },
|
||||
];
|
||||
|
||||
const data = [
|
||||
{ a: '123', b: 'xxxxxxxx', d: 3, key: '1', title: 'hello' },
|
||||
{ a: 'cdd', b: 'edd12221', d: 3, key: '2', title: 'hello' },
|
||||
{ a: '133', c: 'edd12221', d: 2, key: '3', title: 'hello' },
|
||||
{ a: '133', c: 'edd12221', d: 2, key: '4', title: 'hello' },
|
||||
{ a: '133', c: 'edd12221', d: 2, key: '5', title: 'hello' },
|
||||
{ a: '133', c: 'edd12221', d: 2, key: '6', title: 'hello' },
|
||||
{ a: '133', c: 'edd12221', d: 2, key: '7', title: 'hello' },
|
||||
{ a: '133', c: 'edd12221', d: 2, key: '8', title: 'hello' },
|
||||
{ a: '133', c: 'edd12221', d: 2, key: '9', title: 'hello' },
|
||||
];
|
||||
|
||||
ReactDOM.render(
|
||||
<div style={{ width: 800 }}>
|
||||
<h2>Fixed columns</h2>
|
||||
<Table
|
||||
columns={columns}
|
||||
expandedRowRender={record => record.title}
|
||||
expandIconAsCell
|
||||
scroll={{ x: 1200 }}
|
||||
data={data}
|
||||
/>
|
||||
</div>
|
||||
, document.getElementById('__react-content'));
|
|
@ -0,0 +1,45 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const columns = [
|
||||
{ title: 'title1', dataIndex: 'a', key: 'a', width: 100, fixed: 'left' },
|
||||
{ title: 'title2', dataIndex: 'b', key: 'b', width: 100, fixed: 'left' },
|
||||
{ title: 'title3', dataIndex: 'c', key: 'c' },
|
||||
{ title: 'title4', dataIndex: 'b', key: 'd' },
|
||||
{ title: 'title5', dataIndex: 'b', key: 'e' },
|
||||
{ title: 'title6', dataIndex: 'b', key: 'f' },
|
||||
{ title: <div>title7<br /><br /><br />Hello world!</div>, dataIndex: 'b', key: 'g' },
|
||||
{ title: 'title8', dataIndex: 'b', key: 'h' },
|
||||
{ title: 'title9', dataIndex: 'b', key: 'i' },
|
||||
{ title: 'title10', dataIndex: 'b', key: 'j' },
|
||||
{ title: 'title11', dataIndex: 'b', key: 'k' },
|
||||
{ title: 'title12', dataIndex: 'b', key: 'l', width: 100, fixed: 'right' },
|
||||
];
|
||||
|
||||
const data = [
|
||||
{ a: '123', b: 'xxxxxxxx', d: 3, key: '1' },
|
||||
{ a: 'cdd', b: 'edd12221', d: 3, key: '2' },
|
||||
{ a: '133', c: 'edd12221', d: 2, key: '3' },
|
||||
{ a: '133', c: 'edd12221', d: 2, key: '4' },
|
||||
{ a: '133', c: 'edd12221', d: 2, key: '5' },
|
||||
{ a: '133', c: 'edd12221', d: 2, key: '6' },
|
||||
{ a: '133', c: 'edd12221', d: 2, key: '7' },
|
||||
{ a: '133', c: 'edd12221', d: 2, key: '8' },
|
||||
{ a: '133', c: 'edd12221', d: 2, key: '9' },
|
||||
];
|
||||
|
||||
ReactDOM.render(
|
||||
<div style={{ width: 800 }}>
|
||||
<h2>Fixed columns</h2>
|
||||
<Table
|
||||
columns={columns}
|
||||
expandedRowRender={record => record.title}
|
||||
expandIconAsCell
|
||||
scroll={{ x: 1200 }}
|
||||
data={data}
|
||||
/>
|
||||
</div>
|
||||
, document.getElementById('__react-content'));
|
|
@ -0,0 +1,39 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const columns = [
|
||||
{ title: 'title1', dataIndex: 'a', key: 'a', width: 100, fixed: 'left' },
|
||||
{ title: 'title2', dataIndex: 'b', key: 'b', width: 100, fixed: 'left' },
|
||||
{ title: 'title3', dataIndex: 'c', key: 'c', width: 150 },
|
||||
{ title: 'title4', dataIndex: 'c', key: 'd', width: 150 },
|
||||
{ title: 'title5', dataIndex: 'c', key: 'e', width: 150 },
|
||||
{ title: 'title6', dataIndex: 'c', key: 'f', width: 150 },
|
||||
{ title: 'title7', dataIndex: 'c', key: 'g', width: 150 },
|
||||
{ title: 'title8', dataIndex: 'c', key: 'h', width: 150 },
|
||||
{ title: 'title9', dataIndex: 'b', key: 'i', width: 150 },
|
||||
{ title: 'title10', dataIndex: 'b', key: 'j', width: 150 },
|
||||
{ title: 'title11', dataIndex: 'b', key: 'k', width: 150 },
|
||||
{ title: 'title12', dataIndex: 'b', key: 'l', width: 100, fixed: 'right' },
|
||||
];
|
||||
|
||||
const data = [
|
||||
{ a: 'aaa', b: 'bbb', c: '内容内容内容内容内容', d: 3, key: '1' },
|
||||
{ a: 'aaa', b: 'bbb', c: '内容内容内容内容内容', d: 3, key: '2' },
|
||||
{ a: 'aaa', c: '内容内容内容内容内容', d: 2, key: '3' },
|
||||
{ a: 'aaa', c: '内容内容内容内容内容', d: 2, key: '4' },
|
||||
{ a: 'aaa', c: '内容内容内容内容内容', d: 2, key: '5' },
|
||||
{ a: 'aaa', c: '内容内容内容内容内容', d: 2, key: '6' },
|
||||
{ a: 'aaa', c: '内容内容内容内容内容', d: 2, key: '7' },
|
||||
{ a: 'aaa', c: '内容内容内容内容内容', d: 2, key: '8' },
|
||||
{ a: 'aaa', c: '内容内容内容内容内容', d: 2, key: '9' },
|
||||
];
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<h2>Fixed columns and header</h2>
|
||||
<Table columns={columns} scroll={{ x: 1650, y: 300 }} data={data} style={{ width: 800 }} />
|
||||
</div>
|
||||
, document.getElementById('__react-content'));
|
|
@ -0,0 +1,39 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const columns = [
|
||||
{ title: 'title1', dataIndex: 'a', key: 'a', width: 100, fixed: 'left' },
|
||||
{ title: 'title2', dataIndex: 'b', key: 'b', width: 100, fixed: 'left' },
|
||||
{ title: 'titletitle3', dataIndex: 'c', key: 'c' },
|
||||
{ title: 'title4', dataIndex: 'c', key: 'd', width: 150 },
|
||||
{ title: 'title5', dataIndex: 'c', key: 'e', width: 150 },
|
||||
{ title: 'title6', dataIndex: 'c', key: 'f', width: 150 },
|
||||
{ title: 'title7', dataIndex: 'c', key: 'g', width: 150 },
|
||||
{ title: 'title8', dataIndex: 'c', key: 'h', width: 150 },
|
||||
{ title: 'title9', dataIndex: 'b', key: 'i', width: 150 },
|
||||
{ title: 'title10', dataIndex: 'b', key: 'j', width: 150 },
|
||||
{ title: 'title11', dataIndex: 'b', key: 'k', width: 150 },
|
||||
{ title: 'title12', dataIndex: 'b', key: 'l', width: 100, fixed: 'right' },
|
||||
];
|
||||
|
||||
const data = [
|
||||
{ a: 'aaa', b: 'bbb', c: '内容内容内容内容内容', d: 3, key: '1' },
|
||||
{ a: 'aaa', b: 'bbb', c: '内容内容内容内容内容', d: 3, key: '2' },
|
||||
{ a: 'aaa', c: '内容内容内容内容内容', d: 2, key: '3' },
|
||||
{ a: 'aaa', c: '内容内容内容内容内容', d: 2, key: '4' },
|
||||
{ a: 'aaa', c: '内容内容内容内容内容', d: 2, key: '5' },
|
||||
{ a: 'aaa', c: '内容内容内容内容内容', d: 2, key: '6' },
|
||||
{ a: 'aaa', c: '内容内容内容内容内容', d: 2, key: '7' },
|
||||
{ a: 'aaa', c: '内容内容内容内容内容', d: 2, key: '8' },
|
||||
{ a: 'aaa', c: '内容内容内容内容内容', d: 2, key: '9' },
|
||||
];
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<h2>Fixed columns and header, resize window for test</h2>
|
||||
<Table columns={columns} scroll={{ x: '150%', y: 300 }} data={data} />
|
||||
</div>
|
||||
, document.getElementById('__react-content'));
|
|
@ -0,0 +1,45 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const columns = [
|
||||
{ title: 'title1', dataIndex: 'a', key: 'a', width: 100, fixed: 'left' },
|
||||
{ title: 'title2', dataIndex: 'b', key: 'b', width: 100, fixed: 'left' },
|
||||
{ title: 'title3', dataIndex: 'c', key: 'c' },
|
||||
{ title: 'title4', dataIndex: 'b', key: 'd' },
|
||||
{ title: 'title5', dataIndex: 'b', key: 'e' },
|
||||
{ title: 'title6', dataIndex: 'b', key: 'f' },
|
||||
{ title: <div>title7<br /><br /><br />Hello world!</div>, dataIndex: 'b', key: 'g' },
|
||||
{ title: 'title8', dataIndex: 'b', key: 'h' },
|
||||
{ title: 'title9', dataIndex: 'b', key: 'i' },
|
||||
{ title: 'title10', dataIndex: 'b', key: 'j' },
|
||||
{ title: 'title11', dataIndex: 'b', key: 'k' },
|
||||
{ title: 'title12', dataIndex: 'b', key: 'l', width: 100, fixed: 'right' },
|
||||
];
|
||||
|
||||
const data = [
|
||||
{ a: '123', b: 'xxxxxxxx', d: 3, key: '1' },
|
||||
{ a: 'cdd', b: 'edd12221', d: 3, key: '2' },
|
||||
{ a: '133', c: 'edd12221', d: 2, key: '3' },
|
||||
{ a: '133', c: 'edd12221', d: 2, key: '4' },
|
||||
{ a: '133', c: 'edd12221', d: 2, key: '5' },
|
||||
{ a: '133', c: 'edd12221', d: 2, key: '6' },
|
||||
{ a: '133', c: 'edd12221', d: 2, key: '7' },
|
||||
{ a: '133', c: 'edd12221', d: 2, key: '8' },
|
||||
{ a: '133', c: 'edd12221', d: 2, key: '9' },
|
||||
];
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<h2>See fixed columns when you resize window</h2>
|
||||
<Table
|
||||
columns={columns}
|
||||
expandedRowRender={record => record.title}
|
||||
expandIconAsCell
|
||||
scroll={{ x: 800 }}
|
||||
data={data}
|
||||
/>
|
||||
</div>
|
||||
, document.getElementById('__react-content'));
|
|
@ -0,0 +1,100 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
import 'rc-table/assets/bordered.less';
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '姓名',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
title: '其它',
|
||||
children: [
|
||||
{
|
||||
title: '年龄',
|
||||
dataIndex: 'age',
|
||||
key: 'age',
|
||||
},
|
||||
{
|
||||
title: '住址',
|
||||
children: [
|
||||
{
|
||||
title: '街道',
|
||||
dataIndex: 'street',
|
||||
key: 'street',
|
||||
},
|
||||
{
|
||||
title: '小区',
|
||||
children: [
|
||||
{
|
||||
title: '单元',
|
||||
dataIndex: 'building',
|
||||
key: 'building',
|
||||
},
|
||||
{
|
||||
title: '门牌',
|
||||
dataIndex: 'number',
|
||||
key: 'number',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: '公司',
|
||||
children: [
|
||||
{
|
||||
title: '地址',
|
||||
dataIndex: 'companyAddress',
|
||||
key: 'companyAddress',
|
||||
},
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'companyName',
|
||||
key: 'companyName',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: '性别',
|
||||
dataIndex: 'gender',
|
||||
key: 'gender',
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
const data = [{
|
||||
key: '1',
|
||||
name: '胡彦斌',
|
||||
age: 32,
|
||||
street: '拱墅区和睦街道',
|
||||
building: 1,
|
||||
number: 2033,
|
||||
companyAddress: '西湖区湖底公园',
|
||||
companyName: '湖底有限公司',
|
||||
gender: '男',
|
||||
}, {
|
||||
key: '2',
|
||||
name: '胡彦祖',
|
||||
age: 42,
|
||||
street: '拱墅区和睦街道',
|
||||
building: 3,
|
||||
number: 2035,
|
||||
companyAddress: '西湖区湖底公园',
|
||||
companyName: '湖底有限公司',
|
||||
gender: '男',
|
||||
}];
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<h2>grouping columns</h2>
|
||||
<Table columns={columns} data={data} className="bordered" />
|
||||
</div>,
|
||||
document.getElementById('__react-content')
|
||||
);
|
|
@ -0,0 +1,34 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const columns = [
|
||||
{ title: 'title1', dataIndex: 'a', key: 'a', width: 100 },
|
||||
{ id: '123', title: 'title2', dataIndex: 'b', key: 'b', width: 100 },
|
||||
{ title: 'title3', dataIndex: 'c', key: 'c', width: 200 },
|
||||
{
|
||||
title: 'Operations', dataIndex: '', key: 'd', render() {
|
||||
return <a href="#">Operations</a>;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const data = [
|
||||
{ a: '123', key: '1' },
|
||||
{ a: 'cdd', b: 'edd', key: '2' },
|
||||
{ a: '1333', c: 'eee', d: 2, key: '3' },
|
||||
];
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<h2>hide table head</h2>
|
||||
<Table
|
||||
columns={columns}
|
||||
showHeader={false}
|
||||
data={data}
|
||||
/>
|
||||
</div>,
|
||||
document.getElementById('__react-content')
|
||||
);
|
|
@ -0,0 +1,49 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const { ColumnGroup, Column } = Table;
|
||||
|
||||
const data = [
|
||||
{ a: '123', key: '1' },
|
||||
{ a: 'cdd', b: 'edd', key: '2' },
|
||||
{ a: '1333', c: 'eee', d: 2, key: '3' },
|
||||
];
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<h2>JSX table</h2>
|
||||
<Table data={data}>
|
||||
<ColumnGroup title="Bazinga">
|
||||
<Column
|
||||
title="title1"
|
||||
dataIndex="a"
|
||||
key="a"
|
||||
width={100}
|
||||
/>
|
||||
<Column
|
||||
id="123"
|
||||
title="title2"
|
||||
dataIndex="b"
|
||||
key="b"
|
||||
width={100}
|
||||
/>
|
||||
</ColumnGroup>
|
||||
<Column
|
||||
title="title3"
|
||||
dataIndex="c"
|
||||
key="c"
|
||||
width={200}
|
||||
/>
|
||||
<Column
|
||||
title="Operations"
|
||||
dataIndex=""
|
||||
key="d"
|
||||
render={() => <a href="#">Operations</a>}
|
||||
/>
|
||||
</Table>
|
||||
</div>,
|
||||
document.getElementById('__react-content')
|
||||
);
|
|
@ -0,0 +1,70 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const CheckBox = ({ id }) => (
|
||||
<label>
|
||||
<input type="checkbox" />
|
||||
{id}
|
||||
</label>
|
||||
);
|
||||
|
||||
class Demo extends React.Component {
|
||||
static propTypes = {
|
||||
data: PropTypes.array.isRequired,
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
data: props.data,
|
||||
};
|
||||
}
|
||||
|
||||
remove(index) {
|
||||
const rows = this.state.data;
|
||||
rows.splice(index, 1);
|
||||
this.setState({
|
||||
data: rows,
|
||||
});
|
||||
}
|
||||
|
||||
handleClick = (index) => () => {
|
||||
this.remove(index);
|
||||
}
|
||||
|
||||
checkbox(a) {
|
||||
return <CheckBox id={a} />;
|
||||
}
|
||||
|
||||
renderAction = (o, row, index) => {
|
||||
return <a href="#" onClick={this.handleClick(index)}>Delete</a>;
|
||||
}
|
||||
|
||||
render() {
|
||||
const state = this.state;
|
||||
const columns = [
|
||||
{ title: 'title1', dataIndex: 'a', key: 'a', width: 100, render: this.checkbox },
|
||||
{ title: 'title2', dataIndex: 'b', key: 'b', width: 100 },
|
||||
{ title: 'title3', dataIndex: 'c', key: 'c', width: 200 },
|
||||
{ title: 'Operations', dataIndex: '', key: 'x', render: this.renderAction },
|
||||
];
|
||||
return (
|
||||
<Table columns={columns} data={state.data} className="table" rowKey={record => record.a} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const data = [{ a: '123' }, { a: 'cdd', b: 'edd' }, { a: '1333', c: 'eee', d: 2 }];
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<h2>specify key</h2>
|
||||
<Demo data={data} />
|
||||
</div>,
|
||||
document.getElementById('__react-content')
|
||||
);
|
|
@ -0,0 +1,45 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const columns = [
|
||||
{ title: 'First Name', dataIndex: 'names.first', key: 'a', width: 100 },
|
||||
{ title: 'Last Name', dataIndex: 'names.last', key: 'b', width: 100 },
|
||||
{ title: 'Age', dataIndex: 'age', key: 'c', width: 100 },
|
||||
];
|
||||
|
||||
const data = [{
|
||||
age: '23',
|
||||
names: {
|
||||
first: 'John',
|
||||
last: 'Doe',
|
||||
},
|
||||
key: '1',
|
||||
}, {
|
||||
age: '36',
|
||||
names: {
|
||||
first: 'Terry',
|
||||
last: 'Garner',
|
||||
},
|
||||
key: '2',
|
||||
}, {
|
||||
age: '52',
|
||||
names: {
|
||||
first: 'Thomas',
|
||||
last: 'Goodwin',
|
||||
},
|
||||
key: '3',
|
||||
}];
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<h2>Nested data table</h2>
|
||||
<Table
|
||||
columns={columns}
|
||||
data={data}
|
||||
className="table"
|
||||
/>
|
||||
</div>,
|
||||
document.getElementById('__react-content')
|
||||
);
|
|
@ -0,0 +1,26 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const columns = [
|
||||
{ title: 'title1', dataIndex: 'a', key: 'a', width: 100 },
|
||||
{ id: '123', title: 'title2', dataIndex: 'b', key: 'b', width: 100 },
|
||||
{ title: 'title3', dataIndex: 'c', key: 'c', width: 200 },
|
||||
{
|
||||
title: 'Operations', dataIndex: '', key: 'd', render() {
|
||||
return <a href="#">Operations</a>;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const data = [];
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<h2>simple table</h2>
|
||||
<Table columns={columns} data={data} />
|
||||
</div>,
|
||||
document.getElementById('__react-content')
|
||||
);
|
|
@ -0,0 +1,187 @@
|
|||
/* eslint-disable no-unused-expressions,new-cap */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { injectGlobal } from 'styled-components';
|
||||
import update from 'immutability-helper';
|
||||
import { DragDropContext, DragSource, DropTarget } from 'react-dnd';
|
||||
import HTML5Backend from 'react-dnd-html5-backend';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
injectGlobal`
|
||||
tr.drop-over-downward td {
|
||||
border-bottom: 2px dashed red;
|
||||
}
|
||||
|
||||
tr.drop-over-upward td {
|
||||
border-top: 2px dashed red;
|
||||
}
|
||||
`;
|
||||
|
||||
function dragDirection(
|
||||
dragIndex,
|
||||
hoverIndex,
|
||||
initialClientOffset,
|
||||
clientOffset,
|
||||
sourceClientOffset,
|
||||
) {
|
||||
const hoverMiddleY = (initialClientOffset.y - sourceClientOffset.y) / 2;
|
||||
const hoverClientY = clientOffset.y - sourceClientOffset.y;
|
||||
if (dragIndex < hoverIndex && hoverClientY > hoverMiddleY) {
|
||||
return 'downward';
|
||||
}
|
||||
if (dragIndex > hoverIndex && hoverClientY < hoverMiddleY) {
|
||||
return 'upward';
|
||||
}
|
||||
}
|
||||
|
||||
let BodyRow = (props) => {
|
||||
const {
|
||||
isOver,
|
||||
connectDragSource,
|
||||
connectDropTarget,
|
||||
moveRow,
|
||||
dragRow,
|
||||
clientOffset,
|
||||
sourceClientOffset,
|
||||
initialClientOffset,
|
||||
...restProps,
|
||||
} = props;
|
||||
const style = { cursor: 'move' };
|
||||
|
||||
let className = restProps.className;
|
||||
if (isOver && initialClientOffset) {
|
||||
const direction = dragDirection(
|
||||
dragRow.index,
|
||||
restProps.index,
|
||||
initialClientOffset,
|
||||
clientOffset,
|
||||
sourceClientOffset
|
||||
);
|
||||
if (direction === 'downward') {
|
||||
className += ' drop-over-downward';
|
||||
}
|
||||
if (direction === 'upward') {
|
||||
className += ' drop-over-upward';
|
||||
}
|
||||
}
|
||||
|
||||
return connectDragSource(
|
||||
connectDropTarget(
|
||||
<tr
|
||||
{...restProps}
|
||||
className={className}
|
||||
style={style}
|
||||
/>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
const rowSource = {
|
||||
beginDrag(props) {
|
||||
return {
|
||||
index: props.index,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
const rowTarget = {
|
||||
drop(props, monitor) {
|
||||
const dragIndex = monitor.getItem().index;
|
||||
const hoverIndex = props.index;
|
||||
|
||||
// Don't replace items with themselves
|
||||
if (dragIndex === hoverIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Time to actually perform the action
|
||||
props.moveRow(dragIndex, hoverIndex);
|
||||
|
||||
// Note: we're mutating the monitor item here!
|
||||
// Generally it's better to avoid mutations,
|
||||
// but it's good here for the sake of performance
|
||||
// to avoid expensive index searches.
|
||||
monitor.getItem().index = hoverIndex;
|
||||
},
|
||||
};
|
||||
|
||||
BodyRow = DropTarget('row', rowTarget, (connect, monitor) => ({
|
||||
connectDropTarget: connect.dropTarget(),
|
||||
isOver: monitor.isOver(),
|
||||
sourceClientOffset: monitor.getSourceClientOffset(),
|
||||
}))(
|
||||
DragSource('row', rowSource, (connect, monitor) => ({
|
||||
connectDragSource: connect.dragSource(),
|
||||
dragRow: monitor.getItem(),
|
||||
clientOffset: monitor.getClientOffset(),
|
||||
initialClientOffset: monitor.getInitialClientOffset(),
|
||||
}))(BodyRow)
|
||||
);
|
||||
|
||||
const columns = [
|
||||
{ title: 'title1', dataIndex: 'a', key: 'a', width: 100 },
|
||||
{ id: '123', title: 'title2', dataIndex: 'b', key: 'b', width: 100 },
|
||||
{ title: 'title3', dataIndex: 'c', key: 'c', width: 200 },
|
||||
{
|
||||
title: 'Operations',
|
||||
dataIndex: '',
|
||||
key: 'd',
|
||||
render() {
|
||||
return <a href="#">Operations</a>;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
class Demo extends React.Component {
|
||||
state = {
|
||||
data: [
|
||||
{ a: '123', key: '1' },
|
||||
{ a: 'cdd', b: 'edd', key: '2' },
|
||||
{ a: '1333', c: 'eee', d: 2, key: '3' },
|
||||
],
|
||||
}
|
||||
|
||||
components = {
|
||||
body: {
|
||||
row: BodyRow,
|
||||
},
|
||||
}
|
||||
|
||||
moveRow = (dragIndex, hoverIndex) => {
|
||||
const { data } = this.state;
|
||||
const dragRow = data[dragIndex];
|
||||
|
||||
this.setState(
|
||||
update(this.state, {
|
||||
data: {
|
||||
$splice: [[dragIndex, 1], [hoverIndex, 0, dragRow]],
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Table
|
||||
columns={columns}
|
||||
data={this.state.data}
|
||||
components={this.components}
|
||||
onRow={(record, index) => ({
|
||||
index,
|
||||
moveRow: this.moveRow,
|
||||
})}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Demo = DragDropContext(HTML5Backend)(Demo);
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<h2>Integrate with react-dnd</h2>
|
||||
<Demo />
|
||||
</div>,
|
||||
document.getElementById('__react-content')
|
||||
);
|
|
@ -0,0 +1,105 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const onRowClick = (record, index, event) => {
|
||||
console.log(`Click nth(${index}) row of parent, record.name: ${record.name}`);
|
||||
// See https://facebook.github.io/react/docs/events.html for original click event details.
|
||||
if (event.shiftKey) {
|
||||
console.log('Shift + mouse click triggered.');
|
||||
}
|
||||
};
|
||||
|
||||
const onRowDoubleClick = (record, index) => {
|
||||
console.log(`Double click nth(${index}) row of parent, record.name: ${record.name}`);
|
||||
};
|
||||
|
||||
const columns = [{
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
width: 400,
|
||||
}, {
|
||||
title: 'Age',
|
||||
dataIndex: 'age',
|
||||
key: 'age',
|
||||
width: 100,
|
||||
render: (text) => (
|
||||
<span>{text} (Trigger Cell Click)</span>
|
||||
),
|
||||
onCell: (record) => ({
|
||||
onClick(e) {
|
||||
console.log('Click cell', record, e.target);
|
||||
},
|
||||
}),
|
||||
}, {
|
||||
title: 'Address',
|
||||
dataIndex: 'address',
|
||||
key: 'address',
|
||||
width: 200,
|
||||
}];
|
||||
|
||||
const data = [{
|
||||
key: 1,
|
||||
name: 'a',
|
||||
age: 32,
|
||||
address: 'I am a',
|
||||
children: [{
|
||||
key: 11,
|
||||
name: 'aa',
|
||||
age: 33,
|
||||
address: 'I am aa',
|
||||
}, {
|
||||
key: 12,
|
||||
name: 'ab',
|
||||
age: 33,
|
||||
address: 'I am ab',
|
||||
children: [{
|
||||
key: 121,
|
||||
name: 'aba',
|
||||
age: 33,
|
||||
address: 'I am aba',
|
||||
}],
|
||||
}, {
|
||||
key: 13,
|
||||
name: 'ac',
|
||||
age: 33,
|
||||
address: 'I am ac',
|
||||
children: [{
|
||||
key: 131,
|
||||
name: 'aca',
|
||||
age: 33,
|
||||
address: 'I am aca',
|
||||
children: [{
|
||||
key: 1311,
|
||||
name: 'acaa',
|
||||
age: 33,
|
||||
address: 'I am acaa',
|
||||
}, {
|
||||
key: 1312,
|
||||
name: 'acab',
|
||||
age: 33,
|
||||
address: 'I am acab',
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
}, {
|
||||
key: 2,
|
||||
name: 'b',
|
||||
age: 32,
|
||||
address: 'I am b',
|
||||
}];
|
||||
|
||||
ReactDOM.render(
|
||||
<Table
|
||||
columns={columns}
|
||||
data={data}
|
||||
onRow={(record, index) => ({
|
||||
onClick: onRowClick.bind(null, record, index),
|
||||
onDoubleClick: onRowDoubleClick.bind(null, record, index),
|
||||
})}
|
||||
/>,
|
||||
document.getElementById('__react-content')
|
||||
);
|
|
@ -0,0 +1,34 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const columns = [
|
||||
{ title: 'title1', dataIndex: 'a', key: 'a', width: 100 },
|
||||
{ title: 'title2', dataIndex: 'b', key: 'b', width: 100 },
|
||||
{ title: 'title3', dataIndex: 'c', key: 'c', width: 100 },
|
||||
{ title: 'title4', dataIndex: 'b', key: 'd', width: 100 },
|
||||
{ title: 'title5', dataIndex: 'b', key: 'e', width: 100 },
|
||||
{ title: 'title6', dataIndex: 'b', key: 'f', width: 100 },
|
||||
{ title: 'title7', dataIndex: 'b', key: 'g', width: 100 },
|
||||
{ title: 'title8', dataIndex: 'b', key: 'h', width: 100 },
|
||||
{ title: 'title9', dataIndex: 'b', key: 'i', width: 100 },
|
||||
{ title: 'title10', dataIndex: 'b', key: 'j', width: 100 },
|
||||
{ title: 'title11', dataIndex: 'b', key: 'k', width: 100 },
|
||||
{ title: 'title12', dataIndex: 'b', key: 'l', width: 100 },
|
||||
];
|
||||
|
||||
const data = [
|
||||
{ a: '123', b: 'xxxxxxxx xxxxxxxx', d: 3, key: '1' },
|
||||
{ a: 'cdd', b: 'edd12221 edd12221', d: 3, key: '2' },
|
||||
{ a: '133', c: 'edd12221 edd12221', d: 2, key: '3' },
|
||||
{ a: '133', c: 'edd12221 edd12221', d: 2, key: '4' },
|
||||
];
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<h2>Scroll X</h2>
|
||||
<Table style={{ width: 800 }} scroll={{ x: true }} columns={columns} data={data} />
|
||||
</div>
|
||||
, document.getElementById('__react-content'));
|
|
@ -0,0 +1,45 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const columns = [
|
||||
{ title: 'title1', dataIndex: 'a', key: 'a', width: 100 },
|
||||
{ title: 'title2', dataIndex: 'b', key: 'b', width: 100 },
|
||||
{ title: 'title3', dataIndex: 'c', key: 'c', width: 100 },
|
||||
{ title: 'title4', dataIndex: 'b', key: 'd', width: 100 },
|
||||
{ title: 'title5', dataIndex: 'b', key: 'e', width: 100 },
|
||||
{ title: 'title6', dataIndex: 'b', key: 'f', width: 100 },
|
||||
{ title: 'title7', dataIndex: 'b', key: 'g', width: 100 },
|
||||
{ title: 'title8', dataIndex: 'b', key: 'h', width: 100 },
|
||||
{ title: 'title9', dataIndex: 'b', key: 'i', width: 100 },
|
||||
{ title: 'title10', dataIndex: 'b', key: 'j', width: 100 },
|
||||
{ title: 'title11', dataIndex: 'b', key: 'k', width: 100 },
|
||||
{ title: 'title12', dataIndex: 'b', key: 'l', width: 100 },
|
||||
];
|
||||
|
||||
const data = [
|
||||
{ a: '123', b: 'xxxxxxxx xxxxxxxx', d: 3, key: '1' },
|
||||
{ a: 'cdd', b: 'edd12221 edd12221', d: 3, key: '2' },
|
||||
{ a: '133', c: 'edd12221 edd12221', d: 2, key: '3' },
|
||||
{ a: '133', c: 'edd12221 edd12221', d: 2, key: '4' },
|
||||
{ a: '133', c: 'edd12221 edd12221', d: 2, key: '5' },
|
||||
{ a: '133', c: 'edd12221 edd12221', d: 2, key: '6' },
|
||||
{ a: '133', c: 'edd12221 edd12221', d: 2, key: '7' },
|
||||
{ a: '133', c: 'edd12221 edd12221', d: 2, key: '8' },
|
||||
{ a: '133', c: 'edd12221 edd12221', d: 2, key: '9' },
|
||||
];
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<h2>Scroll X/Y</h2>
|
||||
<Table
|
||||
useFixedHeader
|
||||
style={{ width: 800 }}
|
||||
scroll={{ x: 1500, y: 300 }}
|
||||
columns={columns}
|
||||
data={data}
|
||||
/>
|
||||
</div>
|
||||
, document.getElementById('__react-content'));
|
|
@ -0,0 +1,62 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const data = [];
|
||||
for (let i = 0; i < 10; i++) {
|
||||
data.push({
|
||||
key: i,
|
||||
a: `a${i}`,
|
||||
b: `b${i}`,
|
||||
c: `c${i}`,
|
||||
});
|
||||
}
|
||||
|
||||
class Demo extends React.Component {
|
||||
state = {
|
||||
showBody: true,
|
||||
}
|
||||
|
||||
toggleBody = () => {
|
||||
this.setState({
|
||||
showBody: !this.state.showBody,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const columns = [
|
||||
{ title: 'title1', key: 'a', dataIndex: 'a', width: 100 },
|
||||
{ id: '123', title: 'title2', dataIndex: 'b', key: 'b', width: 100 },
|
||||
{ title: 'title3', key: 'c', dataIndex: 'c', width: 200 },
|
||||
{
|
||||
title: <a onClick={this.toggleBody} href="#">{this.state.showBody ? '隐藏' : '显示'}体</a>,
|
||||
key: 'x',
|
||||
width: 200,
|
||||
render() {
|
||||
return <a href="#">Operations</a>;
|
||||
},
|
||||
},
|
||||
];
|
||||
return (
|
||||
<Table
|
||||
columns={columns}
|
||||
data={data}
|
||||
scroll={{ y: 300 }}
|
||||
rowKey={record => record.key}
|
||||
bodyStyle={{
|
||||
display: this.state.showBody ? '' : 'none',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<h2>scroll body table</h2>
|
||||
<Demo />
|
||||
</div>,
|
||||
document.getElementById('__react-content')
|
||||
);
|
|
@ -0,0 +1,30 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const columns = [
|
||||
{ title: 'title1', dataIndex: 'a', key: 'a', width: 100 },
|
||||
{ id: '123', title: 'title2', dataIndex: 'b', key: 'b', width: 100 },
|
||||
{ title: 'title3', dataIndex: 'c', key: 'c', width: 200 },
|
||||
{
|
||||
title: 'Operations', dataIndex: '', key: 'd', render() {
|
||||
return <a href="#">Operations</a>;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const data = [
|
||||
{ a: '123', key: '1' },
|
||||
{ a: 'cdd', b: 'edd', key: '2' },
|
||||
{ a: '1333', c: 'eee', d: 2, key: '3' },
|
||||
];
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<h2>simple table</h2>
|
||||
<Table columns={columns} data={data} />
|
||||
</div>,
|
||||
document.getElementById('__react-content')
|
||||
);
|
|
@ -0,0 +1,45 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import styled from 'styled-components';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const columns = [
|
||||
{ title: 'title1', dataIndex: 'a', key: 'a', width: 100 },
|
||||
{ id: '123', title: 'title2', dataIndex: 'b', key: 'b', width: 100 },
|
||||
{ title: 'title3', dataIndex: 'c', key: 'c', width: 200 },
|
||||
{
|
||||
title: 'Operations',
|
||||
dataIndex: '',
|
||||
key: 'd',
|
||||
render() {
|
||||
return <a href="#">Operations</a>;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const data = [
|
||||
{ a: '123', key: '1' },
|
||||
{ a: 'cdd', b: 'edd', key: '2' },
|
||||
{ a: '1333', c: 'eee', d: 2, key: '3' },
|
||||
];
|
||||
|
||||
const BodyRow = styled.tr`
|
||||
&:hover {
|
||||
background: palevioletred !important;
|
||||
}
|
||||
`;
|
||||
|
||||
const components = {
|
||||
body: {
|
||||
row: BodyRow,
|
||||
},
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<h2>Integrate with styled-components</h2>
|
||||
<Table columns={columns} data={data} components={components} />
|
||||
</div>,
|
||||
document.getElementById('__react-content')
|
||||
);
|
|
@ -0,0 +1,63 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const data = [
|
||||
{
|
||||
a: 'a1',
|
||||
},
|
||||
{
|
||||
a: 'a2',
|
||||
b: 'b2',
|
||||
children: [
|
||||
{
|
||||
a: 'a2-1',
|
||||
b: 'b2-1',
|
||||
},
|
||||
{
|
||||
a: 'a2-2',
|
||||
b: 'b2-2',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
a: 'a3',
|
||||
c: 'c3',
|
||||
d: 'd3',
|
||||
},
|
||||
];
|
||||
|
||||
class Demo extends React.Component {
|
||||
handleClick = (record, e) => {
|
||||
e.preventDefault();
|
||||
console.log(record.a);
|
||||
}
|
||||
|
||||
render() {
|
||||
const columns = [
|
||||
{ title: 'title1', dataIndex: 'a', key: 'a', width: 100 },
|
||||
{ title: 'title2', dataIndex: 'b', key: 'b', width: 100 },
|
||||
{ title: 'title3', dataIndex: 'c', key: 'c', width: 200 },
|
||||
{
|
||||
title: 'Operations', dataIndex: '', key: 'x', render: (text, record) => {
|
||||
return <a href="#" onClick={e => this.handleClick(record, e)}>click {record.a}</a>;
|
||||
},
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div>
|
||||
<h2>sub table</h2>
|
||||
<Table
|
||||
columns={columns}
|
||||
expandIconAsCell
|
||||
data={data}
|
||||
rowKey={record => record.a}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<Demo />, document.getElementById('__react-content'));
|
|
@ -0,0 +1,35 @@
|
|||
/* eslint-disable no-console,func-names,react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Table from 'rc-table';
|
||||
import 'rc-table/assets/index.less';
|
||||
|
||||
const columns = [
|
||||
{ title: 'title1', dataIndex: 'a', key: 'a', width: 100 },
|
||||
{ id: '123', title: 'title2', dataIndex: 'b', key: 'b', width: 100 },
|
||||
{ title: 'title3', dataIndex: 'c', key: 'c', width: 200 },
|
||||
{
|
||||
title: 'Operations', dataIndex: '', key: 'd', render() {
|
||||
return <a href="#">Operations</a>;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const data = [
|
||||
{ a: '123', key: '1' },
|
||||
{ a: 'cdd', b: 'edd', key: '2' },
|
||||
{ a: '1333', c: 'eee', d: 2, key: '3' },
|
||||
];
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<h2>title and footer</h2>
|
||||
<Table
|
||||
columns={columns}
|
||||
data={data}
|
||||
title={currentData => <div>Title: {currentData.length} items</div>}
|
||||
footer={currentData => <div>Footer: {currentData.length} items</div>}
|
||||
/>
|
||||
</div>,
|
||||
document.getElementById('__react-content')
|
||||
);
|
|
@ -0,0 +1,9 @@
|
|||
import Table from './src/Table'
|
||||
import Column from './src/Column'
|
||||
import ColumnGroup from './src/ColumnGroup'
|
||||
|
||||
Table.Column = Column
|
||||
Table.ColumnGroup = ColumnGroup
|
||||
|
||||
export default Table
|
||||
export { Column, ColumnGroup }
|
|
@ -0,0 +1,189 @@
|
|||
|
||||
import PropTypes from '../../_util/vue-types'
|
||||
import ColGroup from './ColGroup'
|
||||
import TableHeader from './TableHeader'
|
||||
import TableRow from './TableRow'
|
||||
import ExpandableRow from './ExpandableRow'
|
||||
import { mergeProps } from '../../_util/props-util'
|
||||
|
||||
const BaseTable = {
|
||||
name: 'BaseTable',
|
||||
props: {
|
||||
fixed: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.bool,
|
||||
]),
|
||||
columns: PropTypes.array.isRequired,
|
||||
tableClassName: PropTypes.string.isRequired,
|
||||
hasHead: PropTypes.bool.isRequired,
|
||||
hasBody: PropTypes.bool.isRequired,
|
||||
store: PropTypes.object.isRequired,
|
||||
expander: PropTypes.object.isRequired,
|
||||
getRowKey: PropTypes.func,
|
||||
isAnyColumnsFixed: PropTypes.bool,
|
||||
},
|
||||
inject: {
|
||||
table: { default: {}},
|
||||
},
|
||||
methods: {
|
||||
handleRowHover (isHover, key) {
|
||||
this.props.store.setState({
|
||||
currentHoverKey: isHover ? key : null,
|
||||
})
|
||||
},
|
||||
|
||||
renderRows (renderData, indent, ancestorKeys = []) {
|
||||
const {
|
||||
columnManager, components,
|
||||
prefixCls,
|
||||
childrenColumnName,
|
||||
rowClassName,
|
||||
// rowRef,
|
||||
$listeners: {
|
||||
rowClick: onRowClick,
|
||||
rowDoubleclick: onRowDoubleClick,
|
||||
rowContextmenu: onRowContextMenu,
|
||||
rowMouseenter: onRowMouseEnter,
|
||||
rowMouseleave: onRowMouseLeave,
|
||||
row: onRow,
|
||||
},
|
||||
} = this.table
|
||||
const { getRowKey, fixed, expander, isAnyColumnsFixed } = this
|
||||
|
||||
const rows = []
|
||||
|
||||
for (let i = 0; i < renderData.length; i++) {
|
||||
const record = renderData[i]
|
||||
const key = getRowKey(record, i)
|
||||
const className = typeof rowClassName === 'string'
|
||||
? rowClassName
|
||||
: rowClassName(record, i, indent)
|
||||
|
||||
const onHoverProps = {}
|
||||
if (columnManager.isAnyColumnsFixed()) {
|
||||
onHoverProps.hover = this.handleRowHover
|
||||
}
|
||||
|
||||
let leafColumns
|
||||
if (fixed === 'left') {
|
||||
leafColumns = columnManager.leftLeafColumns()
|
||||
} else if (fixed === 'right') {
|
||||
leafColumns = columnManager.rightLeafColumns()
|
||||
} else {
|
||||
leafColumns = columnManager.leafColumns()
|
||||
}
|
||||
|
||||
const rowPrefixCls = `${prefixCls}-row`
|
||||
const expandableRowProps = {
|
||||
props: {
|
||||
...expander.props,
|
||||
fixed,
|
||||
index: i,
|
||||
prefixCls: rowPrefixCls,
|
||||
record,
|
||||
rowKey: key,
|
||||
needIndentSpaced: expander.needIndentSpaced,
|
||||
},
|
||||
key,
|
||||
on: {
|
||||
rowClick: onRowClick,
|
||||
expandedChange: expander.handleExpandChange,
|
||||
},
|
||||
scopedSlots: {
|
||||
default: (expandableRow) => {
|
||||
const tableRowProps = mergeProps({
|
||||
props: {
|
||||
fixed,
|
||||
indent,
|
||||
record,
|
||||
index: i,
|
||||
prefixCls: rowPrefixCls,
|
||||
childrenColumnName: childrenColumnName,
|
||||
columns: leafColumns,
|
||||
rowKey: key,
|
||||
ancestorKeys,
|
||||
components,
|
||||
isAnyColumnsFixed,
|
||||
},
|
||||
on: {
|
||||
row: onRow,
|
||||
rowDoubleclick: onRowDoubleClick,
|
||||
rowContextmenu: onRowContextMenu,
|
||||
rowMouseenter: onRowMouseEnter,
|
||||
rowMouseleave: onRowMouseLeave,
|
||||
...onHoverProps,
|
||||
},
|
||||
class: className,
|
||||
ref: `row_${i}_${indent}`,
|
||||
}, expandableRow)
|
||||
return (
|
||||
<TableRow
|
||||
{...tableRowProps}
|
||||
/>
|
||||
)
|
||||
},
|
||||
},
|
||||
}
|
||||
const row = (
|
||||
<ExpandableRow
|
||||
{...expandableRowProps}
|
||||
/>
|
||||
)
|
||||
|
||||
rows.push(row)
|
||||
|
||||
expander.renderRows(
|
||||
this.renderRows,
|
||||
rows,
|
||||
record,
|
||||
i,
|
||||
indent,
|
||||
fixed,
|
||||
key,
|
||||
ancestorKeys
|
||||
)
|
||||
}
|
||||
return rows
|
||||
},
|
||||
},
|
||||
|
||||
render () {
|
||||
const { components, prefixCls, scroll, data, getBodyWrapper } = this.table
|
||||
const { expander, tableClassName, hasHead, hasBody, fixed, columns } = this
|
||||
const tableStyle = {}
|
||||
|
||||
if (!fixed && scroll.x) {
|
||||
// not set width, then use content fixed width
|
||||
if (scroll.x === true) {
|
||||
tableStyle.tableLayout = 'fixed'
|
||||
} else {
|
||||
tableStyle.width = scroll.x
|
||||
}
|
||||
}
|
||||
|
||||
const Table = hasBody ? components.table : 'table'
|
||||
const BodyWrapper = components.body.wrapper
|
||||
|
||||
let body
|
||||
if (hasBody) {
|
||||
body = (
|
||||
<BodyWrapper class={`${prefixCls}-tbody`}>
|
||||
{this.renderRows(data, 0)}
|
||||
</BodyWrapper>
|
||||
)
|
||||
if (getBodyWrapper) {
|
||||
body = getBodyWrapper(body)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Table class={tableClassName} style={tableStyle} key='table'>
|
||||
<ColGroup columns={columns} fixed={fixed} />
|
||||
{hasHead && <TableHeader expander={expander} columns={columns} fixed={fixed} /> }
|
||||
{body}
|
||||
</Table>
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
export default BaseTable
|
|
@ -0,0 +1,117 @@
|
|||
import PropTypes from '../../_util/vue-types'
|
||||
import { measureScrollbar } from './utils'
|
||||
import BaseTable from './BaseTable'
|
||||
|
||||
export default {
|
||||
name: 'BodyTable',
|
||||
props: {
|
||||
fixed: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.bool,
|
||||
]),
|
||||
columns: PropTypes.array.isRequired,
|
||||
tableClassName: PropTypes.string.isRequired,
|
||||
handleBodyScroll: PropTypes.func.isRequired,
|
||||
getRowKey: PropTypes.func.isRequired,
|
||||
expander: PropTypes.object.isRequired,
|
||||
isAnyColumnsFixed: PropTypes.bool,
|
||||
},
|
||||
inject: {
|
||||
table: { default: {}},
|
||||
},
|
||||
render () {
|
||||
const { prefixCls, scroll } = this.table
|
||||
const {
|
||||
columns,
|
||||
fixed,
|
||||
tableClassName,
|
||||
getRowKey,
|
||||
handleBodyScroll,
|
||||
expander,
|
||||
isAnyColumnsFixed,
|
||||
} = this
|
||||
let { useFixedHeader } = this.table
|
||||
const bodyStyle = { ...this.table.bodyStyle }
|
||||
const innerBodyStyle = {}
|
||||
|
||||
if (scroll.x || fixed) {
|
||||
bodyStyle.overflowX = bodyStyle.overflowX || 'auto'
|
||||
// Fix weired webkit render bug
|
||||
// https://github.com/ant-design/ant-design/issues/7783
|
||||
bodyStyle.WebkitTransform = 'translate3d (0, 0, 0)'
|
||||
}
|
||||
|
||||
if (scroll.y) {
|
||||
// maxHeight will make fixed-Table scrolling not working
|
||||
// so we only set maxHeight to body-Table here
|
||||
if (fixed) {
|
||||
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 = measureScrollbar()
|
||||
if (scrollbarWidth > 0 && fixed) {
|
||||
bodyStyle.marginBottom = `-${scrollbarWidth}px`
|
||||
bodyStyle.paddingBottom = '0px'
|
||||
}
|
||||
}
|
||||
|
||||
const baseTable = (
|
||||
<BaseTable
|
||||
tableClassName={tableClassName}
|
||||
hasHead={!useFixedHeader}
|
||||
hasBody
|
||||
fixed={fixed}
|
||||
columns={columns}
|
||||
expander={expander}
|
||||
getRowKey={getRowKey}
|
||||
isAnyColumnsFixed={isAnyColumnsFixed}
|
||||
/>
|
||||
)
|
||||
|
||||
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
|
||||
return (
|
||||
<div
|
||||
key='bodyTable'
|
||||
class={`${prefixCls}-body-outer`}
|
||||
style={{ ...bodyStyle }}
|
||||
>
|
||||
<div
|
||||
class={`${prefixCls}-body-inner`}
|
||||
style={innerBodyStyle}
|
||||
ref={refName}
|
||||
onScroll={handleBodyScroll}
|
||||
>
|
||||
{baseTable}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div
|
||||
key='bodyTable'
|
||||
class={`${prefixCls}-body`}
|
||||
style={bodyStyle}
|
||||
ref='bodyTable'
|
||||
onScroll={handleBodyScroll}
|
||||
>
|
||||
{baseTable}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
import PropTypes from '../../_util/vue-types'
|
||||
|
||||
export default {
|
||||
name: 'ColGroup',
|
||||
props: {
|
||||
fixed: PropTypes.string,
|
||||
},
|
||||
inject: {
|
||||
table: { default: {}},
|
||||
},
|
||||
render () {
|
||||
const { fixed, table } = this
|
||||
const { prefixCls, expandIconAsCell } = table
|
||||
|
||||
let cols = []
|
||||
|
||||
if (expandIconAsCell && fixed !== 'right') {
|
||||
cols.push(
|
||||
<col
|
||||
class={`${prefixCls}-expand-icon-col`}
|
||||
key='rc-table-expand-icon-col'
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
let leafColumns
|
||||
|
||||
if (fixed === 'left') {
|
||||
leafColumns = table.columnManager.leftLeafColumns()
|
||||
} else if (fixed === 'right') {
|
||||
leafColumns = table.columnManager.rightLeafColumns()
|
||||
} else {
|
||||
leafColumns = table.columnManager.leafColumns()
|
||||
}
|
||||
cols = cols.concat(
|
||||
leafColumns.map(c => {
|
||||
return (
|
||||
<col
|
||||
key={c.key || c.dataIndex}
|
||||
style={{ width: c.width, minWidth: c.width }}
|
||||
/>
|
||||
)
|
||||
})
|
||||
)
|
||||
return (
|
||||
<colgroup>
|
||||
{cols}
|
||||
</colgroup>
|
||||
)
|
||||
},
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import PropTypes from '../../_util/vue-types'
|
||||
|
||||
export default {
|
||||
name: 'Column',
|
||||
props: {
|
||||
colSpan: PropTypes.number,
|
||||
title: PropTypes.any,
|
||||
dataIndex: PropTypes.string,
|
||||
width: PropTypes.oneOfType([
|
||||
PropTypes.number,
|
||||
PropTypes.string,
|
||||
]),
|
||||
fixed: PropTypes.oneOf([
|
||||
true,
|
||||
'left',
|
||||
'right',
|
||||
]),
|
||||
render: PropTypes.func,
|
||||
// onCellClick: PropTypes.func,
|
||||
// onCell: PropTypes.func,
|
||||
// onHeaderCell: PropTypes.func,
|
||||
},
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import PropTypes from '../../_util/vue-types'
|
||||
|
||||
export default {
|
||||
name: 'ColumnGroup',
|
||||
props: {
|
||||
title: PropTypes.any,
|
||||
},
|
||||
isTableColumnGroup: true,
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
export default class ColumnManager {
|
||||
_cached = {}
|
||||
|
||||
constructor (columns, elements) {
|
||||
this.columns = columns || this.normalize(elements)
|
||||
}
|
||||
|
||||
isAnyColumnsFixed () {
|
||||
return this._cache('isAnyColumnsFixed', () => {
|
||||
return this.columns.some(column => !!column.fixed)
|
||||
})
|
||||
}
|
||||
|
||||
isAnyColumnsLeftFixed () {
|
||||
return this._cache('isAnyColumnsLeftFixed', () => {
|
||||
return this.columns.some(
|
||||
column => column.fixed === 'left' || column.fixed === true
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
isAnyColumnsRightFixed () {
|
||||
return this._cache('isAnyColumnsRightFixed', () => {
|
||||
return this.columns.some(
|
||||
column => column.fixed === 'right'
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
leftColumns () {
|
||||
return this._cache('leftColumns', () => {
|
||||
return this.groupedColumns().filter(
|
||||
column => column.fixed === 'left' || column.fixed === true
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
rightColumns () {
|
||||
return this._cache('rightColumns', () => {
|
||||
return this.groupedColumns().filter(
|
||||
column => column.fixed === 'right'
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
leafColumns () {
|
||||
return this._cache('leafColumns', () =>
|
||||
this._leafColumns(this.columns)
|
||||
)
|
||||
}
|
||||
|
||||
leftLeafColumns () {
|
||||
return this._cache('leftLeafColumns', () =>
|
||||
this._leafColumns(this.leftColumns())
|
||||
)
|
||||
}
|
||||
|
||||
rightLeafColumns () {
|
||||
return this._cache('rightLeafColumns', () =>
|
||||
this._leafColumns(this.rightColumns())
|
||||
)
|
||||
}
|
||||
|
||||
// add appropriate rowspan and colspan to column
|
||||
groupedColumns () {
|
||||
return this._cache('groupedColumns', () => {
|
||||
const _groupColumns = (columns, currentRow = 0, parentColumn = {}, rows = []) => {
|
||||
// track how many rows we got
|
||||
rows[currentRow] = rows[currentRow] || []
|
||||
const grouped = []
|
||||
const setRowSpan = column => {
|
||||
const rowSpan = rows.length - currentRow
|
||||
if (column &&
|
||||
!column.children && // parent columns are supposed to be one row
|
||||
rowSpan > 1 &&
|
||||
(!column.rowSpan || column.rowSpan < rowSpan)
|
||||
) {
|
||||
column.rowSpan = rowSpan
|
||||
}
|
||||
}
|
||||
columns.forEach((column, index) => {
|
||||
const newColumn = { ...column }
|
||||
rows[currentRow].push(newColumn)
|
||||
parentColumn.colSpan = parentColumn.colSpan || 0
|
||||
if (newColumn.children && newColumn.children.length > 0) {
|
||||
newColumn.children = _groupColumns(newColumn.children, currentRow + 1, newColumn, rows)
|
||||
parentColumn.colSpan = parentColumn.colSpan + newColumn.colSpan
|
||||
} else {
|
||||
parentColumn.colSpan++
|
||||
}
|
||||
// update rowspan to all same row columns
|
||||
for (let i = 0; i < rows[currentRow].length - 1; ++i) {
|
||||
setRowSpan(rows[currentRow][i])
|
||||
}
|
||||
// last column, update rowspan immediately
|
||||
if (index + 1 === columns.length) {
|
||||
setRowSpan(newColumn)
|
||||
}
|
||||
grouped.push(newColumn)
|
||||
})
|
||||
return grouped
|
||||
}
|
||||
return _groupColumns(this.columns)
|
||||
})
|
||||
}
|
||||
|
||||
normalize (elements) {
|
||||
const columns = []
|
||||
elements.forEach(element => {
|
||||
if (!element.tag) {
|
||||
return
|
||||
}
|
||||
debugger
|
||||
const column = { ...element.props }
|
||||
if (element.key) {
|
||||
column.key = element.key
|
||||
}
|
||||
if (element.type.isTableColumnGroup) {
|
||||
column.children = this.normalize(column.children)
|
||||
}
|
||||
columns.push(column)
|
||||
})
|
||||
return columns
|
||||
}
|
||||
|
||||
reset (columns, elements) {
|
||||
this.columns = columns || this.normalize(elements)
|
||||
this._cached = {}
|
||||
}
|
||||
|
||||
_cache (name, fn) {
|
||||
if (name in this._cached) {
|
||||
return this._cached[name]
|
||||
}
|
||||
this._cached[name] = fn()
|
||||
return this._cached[name]
|
||||
}
|
||||
|
||||
_leafColumns (columns) {
|
||||
const leafColumns = []
|
||||
columns.forEach(column => {
|
||||
if (!column.children) {
|
||||
leafColumns.push(column)
|
||||
} else {
|
||||
leafColumns.push(...this._leafColumns(column.children))
|
||||
}
|
||||
})
|
||||
return leafColumns
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
import PropTypes from '../../_util/vue-types'
|
||||
import BaseMixin from '../../_util/BaseMixin'
|
||||
export default {
|
||||
mixins: [BaseMixin],
|
||||
name: 'ExpandIcon',
|
||||
props: {
|
||||
record: PropTypes.object,
|
||||
prefixCls: PropTypes.string,
|
||||
expandable: PropTypes.any,
|
||||
expanded: PropTypes.bool,
|
||||
needIndentSpaced: PropTypes.bool,
|
||||
},
|
||||
methods: {
|
||||
onExpand (e) {
|
||||
this.__emit('expand', this.record, e)
|
||||
},
|
||||
},
|
||||
|
||||
render () {
|
||||
const { expandable, prefixCls, onExpand, needIndentSpaced, expanded } = this
|
||||
if (expandable) {
|
||||
const expandClassName = expanded ? 'expanded' : 'collapsed'
|
||||
return (
|
||||
<span
|
||||
class={`${prefixCls}-expand-icon ${prefixCls}-${expandClassName}`}
|
||||
onClick={onExpand}
|
||||
/>
|
||||
)
|
||||
} else if (needIndentSpaced) {
|
||||
return <span class={`${prefixCls}-expand-icon ${prefixCls}-spaced`} />
|
||||
}
|
||||
return null
|
||||
},
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
import PropTypes from '../../_util/vue-types'
|
||||
import ExpandIcon from './ExpandIcon'
|
||||
import BaseMixin from '../../_util/BaseMixin'
|
||||
|
||||
const ExpandableRow = {
|
||||
mixins: [BaseMixin],
|
||||
name: 'ExpandableRow',
|
||||
props: {
|
||||
prefixCls: PropTypes.string.isRequired,
|
||||
rowKey: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.number,
|
||||
]).isRequired,
|
||||
fixed: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.bool,
|
||||
]),
|
||||
record: PropTypes.object.isRequired,
|
||||
indentSize: PropTypes.number,
|
||||
needIndentSpaced: PropTypes.bool.isRequired,
|
||||
expandRowByClick: PropTypes.bool,
|
||||
expanded: PropTypes.bool.isRequired,
|
||||
expandIconAsCell: PropTypes.bool,
|
||||
expandIconColumnIndex: PropTypes.number,
|
||||
childrenColumnName: PropTypes.string,
|
||||
expandedRowRender: PropTypes.func,
|
||||
// onExpandedChange: PropTypes.func.isRequired,
|
||||
// onRowClick: PropTypes.func,
|
||||
// children: PropTypes.func.isRequired,
|
||||
},
|
||||
|
||||
beforeDestroy () {
|
||||
this.handleDestroy()
|
||||
},
|
||||
|
||||
hasExpandIcon (columnIndex) {
|
||||
const { expandRowByClick } = this
|
||||
return !this.expandIconAsCell &&
|
||||
!expandRowByClick &&
|
||||
columnIndex === this.expandIconColumnIndex
|
||||
},
|
||||
|
||||
handleExpandChange (record, event) {
|
||||
const { expanded, rowKey } = this
|
||||
this.__emit('expandedChange', !expanded, record, event, rowKey)
|
||||
},
|
||||
|
||||
handleDestroy () {
|
||||
const { rowKey, record } = this
|
||||
this.__emit('expandedChange', false, record, null, rowKey, true)
|
||||
},
|
||||
|
||||
handleRowClick (record, index, event) {
|
||||
const { expandRowByClick } = this
|
||||
if (expandRowByClick) {
|
||||
this.handleExpandChange(record, event)
|
||||
}
|
||||
this.__emit('rowClick', record, index, event)
|
||||
},
|
||||
|
||||
renderExpandIcon () {
|
||||
const { prefixCls, expanded, record, needIndentSpaced } = this
|
||||
|
||||
return (
|
||||
<ExpandIcon
|
||||
expandable={this.expandable}
|
||||
prefixCls={prefixCls}
|
||||
onExpand={this.handleExpandChange}
|
||||
needIndentSpaced={needIndentSpaced}
|
||||
expanded={expanded}
|
||||
record={record}
|
||||
/>
|
||||
)
|
||||
},
|
||||
|
||||
renderExpandIconCell (cells) {
|
||||
if (!this.expandIconAsCell) {
|
||||
return
|
||||
}
|
||||
const { prefixCls } = this
|
||||
|
||||
cells.push(
|
||||
<td
|
||||
class={`${prefixCls}-expand-icon-cell`}
|
||||
key='rc-table-expand-icon-cell'
|
||||
>
|
||||
{this.renderExpandIcon()}
|
||||
</td>
|
||||
)
|
||||
},
|
||||
|
||||
render () {
|
||||
const {
|
||||
childrenColumnName,
|
||||
expandedRowRender,
|
||||
indentSize,
|
||||
record,
|
||||
fixed,
|
||||
$scopedSlots,
|
||||
} = this
|
||||
|
||||
this.expandIconAsCell = fixed !== 'right' ? this.expandIconAsCell : false
|
||||
this.expandIconColumnIndex = fixed !== 'right' ? this.expandIconColumnIndex : -1
|
||||
const childrenData = record[childrenColumnName]
|
||||
this.expandable = !!(childrenData || expandedRowRender)
|
||||
|
||||
const expandableRowProps = {
|
||||
props: {
|
||||
indentSize,
|
||||
hasExpandIcon: this.hasExpandIcon,
|
||||
renderExpandIcon: this.renderExpandIcon,
|
||||
renderExpandIconCell: this.renderExpandIconCell,
|
||||
},
|
||||
on: {
|
||||
rowClick: this.handleRowClick,
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
return $scopedSlots.default && $scopedSlots.default(expandableRowProps)
|
||||
},
|
||||
}
|
||||
|
||||
export default connect(({ expandedRowKeys }, { rowKey }) => ({
|
||||
expanded: !!~expandedRowKeys.indexOf(rowKey),
|
||||
}))(ExpandableRow)
|
|
@ -0,0 +1,223 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'mini-store'
|
||||
import TableRow from './TableRow'
|
||||
import { remove } from './utils'
|
||||
|
||||
class ExpandableTable extends React.Component {
|
||||
static propTypes = {
|
||||
expandIconAsCell: PropTypes.bool,
|
||||
expandedRowKeys: PropTypes.array,
|
||||
expandedRowClassName: PropTypes.func,
|
||||
defaultExpandAllRows: PropTypes.bool,
|
||||
defaultExpandedRowKeys: PropTypes.array,
|
||||
expandIconColumnIndex: PropTypes.number,
|
||||
expandedRowRender: PropTypes.func,
|
||||
childrenColumnName: PropTypes.string,
|
||||
indentSize: PropTypes.number,
|
||||
onExpand: PropTypes.func,
|
||||
onExpandedRowsChange: PropTypes.func,
|
||||
columnManager: PropTypes.object.isRequired,
|
||||
store: PropTypes.object.isRequired,
|
||||
prefixCls: PropTypes.string.isRequired,
|
||||
data: PropTypes.array,
|
||||
children: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
expandIconAsCell: false,
|
||||
expandedRowClassName: () => '',
|
||||
expandIconColumnIndex: 0,
|
||||
defaultExpandAllRows: false,
|
||||
defaultExpandedRowKeys: [],
|
||||
childrenColumnName: 'children',
|
||||
indentSize: 15,
|
||||
onExpand () {},
|
||||
onExpandedRowsChange () {},
|
||||
}
|
||||
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
const {
|
||||
data,
|
||||
childrenColumnName,
|
||||
defaultExpandAllRows,
|
||||
expandedRowKeys,
|
||||
defaultExpandedRowKeys,
|
||||
getRowKey,
|
||||
} = props
|
||||
|
||||
let finnalExpandedRowKeys = []
|
||||
let rows = [...data]
|
||||
|
||||
if (defaultExpandAllRows) {
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
const row = rows[i]
|
||||
finnalExpandedRowKeys.push(getRowKey(row, i))
|
||||
rows = rows.concat(row[childrenColumnName] || [])
|
||||
}
|
||||
} else {
|
||||
finnalExpandedRowKeys = expandedRowKeys || defaultExpandedRowKeys
|
||||
}
|
||||
|
||||
this.columnManager = props.columnManager
|
||||
this.store = props.store
|
||||
|
||||
this.store.setState({
|
||||
expandedRowsHeight: {},
|
||||
expandedRowKeys: finnalExpandedRowKeys,
|
||||
})
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
if ('expandedRowKeys' in nextProps) {
|
||||
this.store.setState({
|
||||
expandedRowKeys: nextProps.expandedRowKeys,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleExpandChange = (expanded, record, event, rowKey, destroy = false) => {
|
||||
if (event) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
}
|
||||
|
||||
const { onExpandedRowsChange, onExpand } = this.props
|
||||
let { expandedRowKeys } = this.store.getState()
|
||||
|
||||
if (expanded) {
|
||||
// row was expaned
|
||||
expandedRowKeys = [...expandedRowKeys, rowKey]
|
||||
} else {
|
||||
// row was collapse
|
||||
const expandedRowIndex = expandedRowKeys.indexOf(rowKey)
|
||||
if (expandedRowIndex !== -1) {
|
||||
expandedRowKeys = remove(expandedRowKeys, rowKey)
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.props.expandedRowKeys) {
|
||||
this.store.setState({ expandedRowKeys })
|
||||
}
|
||||
|
||||
onExpandedRowsChange(expandedRowKeys)
|
||||
if (!destroy) {
|
||||
onExpand(expanded, record)
|
||||
}
|
||||
}
|
||||
|
||||
renderExpandIndentCell = (rows, fixed) => {
|
||||
const { prefixCls, expandIconAsCell } = this.props
|
||||
if (!expandIconAsCell || fixed === 'right' || !rows.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const iconColumn = {
|
||||
key: 'rc-table-expand-icon-cell',
|
||||
className: `${prefixCls}-expand-icon-th`,
|
||||
title: '',
|
||||
rowSpan: rows.length,
|
||||
}
|
||||
|
||||
rows[0].unshift({ ...iconColumn, column: iconColumn })
|
||||
}
|
||||
|
||||
renderExpandedRow (record, index, render, className, ancestorKeys, indent, fixed) {
|
||||
const { prefixCls, expandIconAsCell, indentSize } = 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
|
||||
}
|
||||
const columns = [{
|
||||
key: 'extra-row',
|
||||
render: () => ({
|
||||
props: {
|
||||
colSpan: colCount,
|
||||
},
|
||||
children: fixed !== 'right' ? render(record, index, indent) : ' ',
|
||||
}),
|
||||
}]
|
||||
if (expandIconAsCell && fixed !== 'right') {
|
||||
columns.unshift({
|
||||
key: 'expand-icon-placeholder',
|
||||
render: () => null,
|
||||
})
|
||||
}
|
||||
const parentKey = ancestorKeys[ancestorKeys.length - 1]
|
||||
const rowKey = `${parentKey}-extra-row`
|
||||
const components = {
|
||||
body: {
|
||||
row: 'tr',
|
||||
cell: 'td',
|
||||
},
|
||||
}
|
||||
|
||||
return (
|
||||
<TableRow
|
||||
key={rowKey}
|
||||
columns={columns}
|
||||
className={className}
|
||||
rowKey={rowKey}
|
||||
ancestorKeys={ancestorKeys}
|
||||
prefixCls={`${prefixCls}-expanded-row`}
|
||||
indentSize={indentSize}
|
||||
indent={indent}
|
||||
fixed={fixed}
|
||||
components={components}
|
||||
expandedRow
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
renderRows = (renderRows, rows, record, index, indent, fixed, parentKey, ancestorKeys) => {
|
||||
const { expandedRowClassName, expandedRowRender, childrenColumnName } = this.props
|
||||
const childrenData = record[childrenColumnName]
|
||||
const nextAncestorKeys = [...ancestorKeys, parentKey]
|
||||
const nextIndent = indent + 1
|
||||
|
||||
if (expandedRowRender) {
|
||||
rows.push(
|
||||
this.renderExpandedRow(
|
||||
record,
|
||||
index,
|
||||
expandedRowRender,
|
||||
expandedRowClassName(record, index, indent),
|
||||
nextAncestorKeys,
|
||||
nextIndent,
|
||||
fixed,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if (childrenData) {
|
||||
rows.push(
|
||||
...renderRows(
|
||||
childrenData,
|
||||
nextIndent,
|
||||
nextAncestorKeys,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const { data, childrenColumnName, children } = this.props
|
||||
const needIndentSpaced = data.some(record => record[childrenColumnName])
|
||||
|
||||
return children({
|
||||
props: this.props,
|
||||
needIndentSpaced,
|
||||
renderRows: this.renderRows,
|
||||
handleExpandChange: this.handleExpandChange,
|
||||
renderExpandIndentCell: this.renderExpandIndentCell,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default connect()(ExpandableTable)
|
|
@ -0,0 +1,56 @@
|
|||
import PropTypes from '../../_util/vue-types'
|
||||
import { measureScrollbar } from './utils'
|
||||
import BaseTable from './BaseTable'
|
||||
|
||||
export default {
|
||||
name: 'HeadTable',
|
||||
props: {
|
||||
fixed: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.bool,
|
||||
]),
|
||||
columns: PropTypes.array.isRequired,
|
||||
tableClassName: PropTypes.string.isRequired,
|
||||
handleBodyScrollLeft: PropTypes.func.isRequired,
|
||||
expander: PropTypes.object.isRequired,
|
||||
},
|
||||
render () {
|
||||
const { columns, fixed, tableClassName, handleBodyScrollLeft, expander, table } = this
|
||||
const { prefixCls, scroll, showHeader } = table
|
||||
let { useFixedHeader } = table
|
||||
const headStyle = {}
|
||||
|
||||
if (scroll.y) {
|
||||
useFixedHeader = true
|
||||
// Add negative margin bottom for scroll bar overflow bug
|
||||
const scrollbarWidth = measureScrollbar('horizontal')
|
||||
if (scrollbarWidth > 0 && !fixed) {
|
||||
headStyle.marginBottom = `-${scrollbarWidth}px`
|
||||
headStyle.paddingBottom = '0px'
|
||||
}
|
||||
}
|
||||
|
||||
if (!useFixedHeader || !showHeader) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<div
|
||||
key='headTable'
|
||||
ref={fixed ? null : 'headTable'}
|
||||
class={`${prefixCls}-header`}
|
||||
style={headStyle}
|
||||
onScroll={handleBodyScrollLeft}
|
||||
>
|
||||
<BaseTable
|
||||
tableClassName={tableClassName}
|
||||
hasHead
|
||||
hasBody={false}
|
||||
fixed={fixed}
|
||||
columns={columns}
|
||||
expander={expander}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
|
||||
}
|
|
@ -0,0 +1,475 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { debounce, warningOnce } from './utils'
|
||||
import shallowequal from 'shallowequal'
|
||||
import addEventListener from 'rc-util/lib/Dom/addEventListener'
|
||||
import { Provider, create } from 'mini-store'
|
||||
import merge from 'lodash/merge'
|
||||
import ColumnManager from './ColumnManager'
|
||||
import classes from 'component-classes'
|
||||
import HeadTable from './HeadTable'
|
||||
import BodyTable from './BodyTable'
|
||||
import ExpandableTable from './ExpandableTable'
|
||||
|
||||
export default class Table extends React.Component {
|
||||
static propTypes = {
|
||||
data: PropTypes.array,
|
||||
useFixedHeader: PropTypes.bool,
|
||||
columns: PropTypes.array,
|
||||
prefixCls: PropTypes.string,
|
||||
bodyStyle: PropTypes.object,
|
||||
style: PropTypes.object,
|
||||
rowKey: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||
rowClassName: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||
onRow: PropTypes.func,
|
||||
onHeaderRow: PropTypes.func,
|
||||
onRowClick: PropTypes.func,
|
||||
onRowDoubleClick: PropTypes.func,
|
||||
onRowContextMenu: PropTypes.func,
|
||||
onRowMouseEnter: PropTypes.func,
|
||||
onRowMouseLeave: PropTypes.func,
|
||||
showHeader: PropTypes.bool,
|
||||
title: PropTypes.func,
|
||||
id: PropTypes.string,
|
||||
footer: PropTypes.func,
|
||||
emptyText: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
|
||||
scroll: PropTypes.object,
|
||||
rowRef: PropTypes.func,
|
||||
getBodyWrapper: PropTypes.func,
|
||||
children: PropTypes.node,
|
||||
components: PropTypes.shape({
|
||||
table: PropTypes.any,
|
||||
header: PropTypes.shape({
|
||||
wrapper: PropTypes.any,
|
||||
row: PropTypes.any,
|
||||
cell: PropTypes.any,
|
||||
}),
|
||||
body: PropTypes.shape({
|
||||
wrapper: PropTypes.any,
|
||||
row: PropTypes.any,
|
||||
cell: PropTypes.any,
|
||||
}),
|
||||
}),
|
||||
...ExpandableTable.PropTypes,
|
||||
}
|
||||
|
||||
static childContextTypes = {
|
||||
table: PropTypes.any,
|
||||
components: PropTypes.any,
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
data: [],
|
||||
useFixedHeader: false,
|
||||
rowKey: 'key',
|
||||
rowClassName: () => '',
|
||||
onRow () {},
|
||||
onHeaderRow () {},
|
||||
prefixCls: 'rc-table',
|
||||
bodyStyle: {},
|
||||
style: {},
|
||||
showHeader: true,
|
||||
scroll: {},
|
||||
rowRef: () => null,
|
||||
emptyText: () => 'No Data',
|
||||
}
|
||||
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
[
|
||||
'onRowClick',
|
||||
'onRowDoubleClick',
|
||||
'onRowContextMenu',
|
||||
'onRowMouseEnter',
|
||||
'onRowMouseLeave',
|
||||
].forEach(name => {
|
||||
warningOnce(
|
||||
props[name] === undefined,
|
||||
`${name} is deprecated, please use onRow instead.`,
|
||||
)
|
||||
})
|
||||
|
||||
warningOnce(
|
||||
props.getBodyWrapper === undefined,
|
||||
'getBodyWrapper is deprecated, please use custom components instead.',
|
||||
)
|
||||
|
||||
this.columnManager = new ColumnManager(props.columns, props.children)
|
||||
|
||||
this.store = create({
|
||||
currentHoverKey: null,
|
||||
fixedColumnsHeadRowsHeight: [],
|
||||
fixedColumnsBodyRowsHeight: [],
|
||||
})
|
||||
|
||||
this.setScrollPosition('left')
|
||||
|
||||
this.debouncedWindowResize = debounce(this.handleWindowResize, 150)
|
||||
}
|
||||
|
||||
getChildContext () {
|
||||
return {
|
||||
table: {
|
||||
props: this.props,
|
||||
columnManager: this.columnManager,
|
||||
saveRef: this.saveRef,
|
||||
components: merge({
|
||||
table: 'table',
|
||||
header: {
|
||||
wrapper: 'thead',
|
||||
row: 'tr',
|
||||
cell: 'th',
|
||||
},
|
||||
body: {
|
||||
wrapper: 'tbody',
|
||||
row: 'tr',
|
||||
cell: 'td',
|
||||
},
|
||||
}, this.props.components),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
if (this.columnManager.isAnyColumnsFixed()) {
|
||||
this.handleWindowResize()
|
||||
this.resizeEvent = addEventListener(
|
||||
window, 'resize', this.debouncedWindowResize
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
if (nextProps.columns && nextProps.columns !== this.props.columns) {
|
||||
this.columnManager.reset(nextProps.columns)
|
||||
} else if (nextProps.children !== this.props.children) {
|
||||
this.columnManager.reset(null, nextProps.children)
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
if (this.columnManager.isAnyColumnsFixed()) {
|
||||
this.handleWindowResize()
|
||||
if (!this.resizeEvent) {
|
||||
this.resizeEvent = addEventListener(
|
||||
window, 'resize', this.debouncedWindowResize
|
||||
)
|
||||
}
|
||||
}
|
||||
// when table changes to empty, reset scrollLeft
|
||||
if (prevProps.data.length > 0 && this.props.data.length === 0 && this.hasScrollX()) {
|
||||
this.resetScrollX()
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
if (this.resizeEvent) {
|
||||
this.resizeEvent.remove()
|
||||
}
|
||||
if (this.debouncedWindowResize) {
|
||||
this.debouncedWindowResize.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
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 === undefined ? index : key
|
||||
}
|
||||
|
||||
setScrollPosition (position) {
|
||||
this.scrollPosition = position
|
||||
if (this.tableNode) {
|
||||
const { prefixCls } = this.props
|
||||
if (position === 'both') {
|
||||
classes(this.tableNode)
|
||||
.remove(new RegExp(`^${prefixCls}-scroll-position-.+$`))
|
||||
.add(`${prefixCls}-scroll-position-left`)
|
||||
.add(`${prefixCls}-scroll-position-right`)
|
||||
} else {
|
||||
classes(this.tableNode)
|
||||
.remove(new RegExp(`^${prefixCls}-scroll-position-.+$`))
|
||||
.add(`${prefixCls}-scroll-position-${position}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setScrollPositionClassName () {
|
||||
const node = this.bodyTable
|
||||
const scrollToLeft = node.scrollLeft === 0
|
||||
const scrollToRight = node.scrollLeft + 1 >=
|
||||
node.children[0].getBoundingClientRect().width -
|
||||
node.getBoundingClientRect().width
|
||||
if (scrollToLeft && scrollToRight) {
|
||||
this.setScrollPosition('both')
|
||||
} else if (scrollToLeft) {
|
||||
this.setScrollPosition('left')
|
||||
} else if (scrollToRight) {
|
||||
this.setScrollPosition('right')
|
||||
} else if (this.scrollPosition !== 'middle') {
|
||||
this.setScrollPosition('middle')
|
||||
}
|
||||
}
|
||||
|
||||
handleWindowResize = () => {
|
||||
this.syncFixedTableRowHeight()
|
||||
this.setScrollPositionClassName()
|
||||
}
|
||||
|
||||
syncFixedTableRowHeight = () => {
|
||||
const tableRect = this.tableNode.getBoundingClientRect()
|
||||
// If tableNode's height less than 0, suppose it is hidden and don't recalculate rowHeight.
|
||||
// see: https://github.com/ant-design/ant-design/issues/4836
|
||||
if (tableRect.height !== undefined && tableRect.height <= 0) {
|
||||
return
|
||||
}
|
||||
const { prefixCls } = this.props
|
||||
const headRows = this.headTable
|
||||
? this.headTable.querySelectorAll('thead')
|
||||
: this.bodyTable.querySelectorAll('thead')
|
||||
const bodyRows = this.bodyTable.querySelectorAll(`.${prefixCls}-row`) || []
|
||||
const fixedColumnsHeadRowsHeight = [].map.call(
|
||||
headRows, row => row.getBoundingClientRect().height || 'auto'
|
||||
)
|
||||
const fixedColumnsBodyRowsHeight = [].map.call(
|
||||
bodyRows, row => row.getBoundingClientRect().height || 'auto'
|
||||
)
|
||||
const state = this.store.getState()
|
||||
if (shallowequal(state.fixedColumnsHeadRowsHeight, fixedColumnsHeadRowsHeight) &&
|
||||
shallowequal(state.fixedColumnsBodyRowsHeight, fixedColumnsBodyRowsHeight)) {
|
||||
return
|
||||
}
|
||||
|
||||
this.store.setState({
|
||||
fixedColumnsHeadRowsHeight,
|
||||
fixedColumnsBodyRowsHeight,
|
||||
})
|
||||
}
|
||||
|
||||
resetScrollX () {
|
||||
if (this.headTable) {
|
||||
this.headTable.scrollLeft = 0
|
||||
}
|
||||
if (this.bodyTable) {
|
||||
this.bodyTable.scrollLeft = 0
|
||||
}
|
||||
}
|
||||
|
||||
hasScrollX () {
|
||||
const { scroll = {}} = this.props
|
||||
return 'x' in scroll
|
||||
}
|
||||
|
||||
handleBodyScrollLeft = (e) => {
|
||||
// Fix https://github.com/ant-design/ant-design/issues/7635
|
||||
if (e.currentTarget !== e.target) {
|
||||
return
|
||||
}
|
||||
const target = e.target
|
||||
const { scroll = {}} = this.props
|
||||
const { headTable, bodyTable } = this
|
||||
if (target.scrollLeft !== this.lastScrollLeft && scroll.x) {
|
||||
if (target === bodyTable && headTable) {
|
||||
headTable.scrollLeft = target.scrollLeft
|
||||
} else if (target === headTable && bodyTable) {
|
||||
bodyTable.scrollLeft = target.scrollLeft
|
||||
}
|
||||
this.setScrollPositionClassName()
|
||||
}
|
||||
// Remember last scrollLeft for scroll direction detecting.
|
||||
this.lastScrollLeft = target.scrollLeft
|
||||
}
|
||||
|
||||
handleBodyScrollTop = (e) => {
|
||||
const target = e.target
|
||||
const { scroll = {}} = this.props
|
||||
const { headTable, bodyTable, fixedColumnsBodyLeft, fixedColumnsBodyRight } = this
|
||||
if (target.scrollTop !== this.lastScrollTop && scroll.y && target !== headTable) {
|
||||
const scrollTop = target.scrollTop
|
||||
if (fixedColumnsBodyLeft && target !== fixedColumnsBodyLeft) {
|
||||
fixedColumnsBodyLeft.scrollTop = scrollTop
|
||||
}
|
||||
if (fixedColumnsBodyRight && target !== fixedColumnsBodyRight) {
|
||||
fixedColumnsBodyRight.scrollTop = scrollTop
|
||||
}
|
||||
if (bodyTable && target !== bodyTable) {
|
||||
bodyTable.scrollTop = scrollTop
|
||||
}
|
||||
}
|
||||
// Remember last scrollTop for scroll direction detecting.
|
||||
this.lastScrollTop = target.scrollTop
|
||||
}
|
||||
|
||||
handleBodyScroll = (e) => {
|
||||
this.handleBodyScrollLeft(e)
|
||||
this.handleBodyScrollTop(e)
|
||||
}
|
||||
|
||||
saveRef = (name) => (node) => {
|
||||
this[name] = node
|
||||
}
|
||||
|
||||
renderMainTable () {
|
||||
const { scroll, prefixCls } = this.props
|
||||
const isAnyColumnsFixed = this.columnManager.isAnyColumnsFixed()
|
||||
const scrollable = isAnyColumnsFixed || scroll.x || scroll.y
|
||||
|
||||
const table = [
|
||||
this.renderTable({
|
||||
columns: this.columnManager.groupedColumns(),
|
||||
isAnyColumnsFixed,
|
||||
}),
|
||||
this.renderEmptyText(),
|
||||
this.renderFooter(),
|
||||
]
|
||||
|
||||
return scrollable ? (
|
||||
<div className={`${prefixCls}-scroll`}>{table}</div>
|
||||
) : table
|
||||
}
|
||||
|
||||
renderLeftFixedTable () {
|
||||
const { prefixCls } = this.props
|
||||
|
||||
return (
|
||||
<div className={`${prefixCls}-fixed-left`}>
|
||||
{this.renderTable({
|
||||
columns: this.columnManager.leftColumns(),
|
||||
fixed: 'left',
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
renderRightFixedTable () {
|
||||
const { prefixCls } = this.props
|
||||
|
||||
return (
|
||||
<div className={`${prefixCls}-fixed-right`}>
|
||||
{this.renderTable({
|
||||
columns: this.columnManager.rightColumns(),
|
||||
fixed: 'right',
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
renderTable (options) {
|
||||
const { columns, fixed, isAnyColumnsFixed } = options
|
||||
const { prefixCls, scroll = {}} = this.props
|
||||
const tableClassName = (scroll.x || fixed) ? `${prefixCls}-fixed` : ''
|
||||
|
||||
const headTable = (
|
||||
<HeadTable
|
||||
key='head'
|
||||
columns={columns}
|
||||
fixed={fixed}
|
||||
tableClassName={tableClassName}
|
||||
handleBodyScrollLeft={this.handleBodyScrollLeft}
|
||||
expander={this.expander}
|
||||
/>
|
||||
)
|
||||
|
||||
const bodyTable = (
|
||||
<BodyTable
|
||||
key='body'
|
||||
columns={columns}
|
||||
fixed={fixed}
|
||||
tableClassName={tableClassName}
|
||||
getRowKey={this.getRowKey}
|
||||
handleBodyScroll={this.handleBodyScroll}
|
||||
expander={this.expander}
|
||||
isAnyColumnsFixed={isAnyColumnsFixed}
|
||||
/>
|
||||
)
|
||||
|
||||
return [headTable, bodyTable]
|
||||
}
|
||||
|
||||
renderTitle () {
|
||||
const { title, prefixCls } = this.props
|
||||
return title ? (
|
||||
<div className={`${prefixCls}-title`} key='title'>
|
||||
{title(this.props.data)}
|
||||
</div>
|
||||
) : null
|
||||
}
|
||||
|
||||
renderFooter () {
|
||||
const { footer, prefixCls } = this.props
|
||||
return footer ? (
|
||||
<div className={`${prefixCls}-footer`} key='footer'>
|
||||
{footer(this.props.data)}
|
||||
</div>
|
||||
) : null
|
||||
}
|
||||
|
||||
renderEmptyText () {
|
||||
const { emptyText, prefixCls, data } = this.props
|
||||
if (data.length) {
|
||||
return null
|
||||
}
|
||||
const emptyClassName = `${prefixCls}-placeholder`
|
||||
return (
|
||||
<div className={emptyClassName} key='emptyText'>
|
||||
{(typeof emptyText === 'function') ? emptyText() : emptyText}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
render () {
|
||||
const props = this.props
|
||||
const prefixCls = props.prefixCls
|
||||
|
||||
let className = props.prefixCls
|
||||
if (props.className) {
|
||||
className += ` ${props.className}`
|
||||
}
|
||||
if (props.useFixedHeader || (props.scroll && props.scroll.y)) {
|
||||
className += ` ${prefixCls}-fixed-header`
|
||||
}
|
||||
if (this.scrollPosition === 'both') {
|
||||
className += ` ${prefixCls}-scroll-position-left ${prefixCls}-scroll-position-right`
|
||||
} else {
|
||||
className += ` ${prefixCls}-scroll-position-${this.scrollPosition}`
|
||||
}
|
||||
const hasLeftFixed = this.columnManager.isAnyColumnsLeftFixed()
|
||||
const hasRightFixed = this.columnManager.isAnyColumnsRightFixed()
|
||||
|
||||
return (
|
||||
<Provider store={this.store}>
|
||||
<ExpandableTable
|
||||
{...props}
|
||||
columnManager={this.columnManager}
|
||||
getRowKey={this.getRowKey}
|
||||
>
|
||||
{(expander) => {
|
||||
this.expander = expander
|
||||
return (
|
||||
<div
|
||||
ref={this.saveRef('tableNode')}
|
||||
className={className}
|
||||
style={props.style}
|
||||
id={props.id}
|
||||
>
|
||||
{this.renderTitle()}
|
||||
<div className={`${prefixCls}-content`}>
|
||||
{this.renderMainTable()}
|
||||
{hasLeftFixed && this.renderLeftFixedTable()}
|
||||
{hasRightFixed && this.renderRightFixedTable()}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</ExpandableTable>
|
||||
</Provider>
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
import PropTypes from '../../_util/vue-types'
|
||||
import get from 'lodash/get'
|
||||
|
||||
export default {
|
||||
name: 'TableCell',
|
||||
props: {
|
||||
record: PropTypes.object,
|
||||
prefixCls: PropTypes.string,
|
||||
index: PropTypes.number,
|
||||
indent: PropTypes.number,
|
||||
indentSize: PropTypes.number,
|
||||
column: PropTypes.object,
|
||||
expandIcon: PropTypes.node,
|
||||
component: PropTypes.any,
|
||||
},
|
||||
methods: {
|
||||
isInvalidRenderCellText (text) {
|
||||
debugger
|
||||
return text &&
|
||||
Object.prototype.toString.call(text) === '[object Object]'
|
||||
},
|
||||
|
||||
handleClick (e) {
|
||||
const { record, column: { onCellClick }} = this
|
||||
if (onCellClick) {
|
||||
onCellClick(record, e)
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
render () {
|
||||
const {
|
||||
record,
|
||||
indentSize,
|
||||
prefixCls,
|
||||
indent,
|
||||
index,
|
||||
expandIcon,
|
||||
column,
|
||||
component: BodyCell,
|
||||
} = this
|
||||
const { dataIndex, render } = column
|
||||
|
||||
// We should return undefined if no dataIndex is specified, but in order to
|
||||
// be compatible with object-path's behavior, we return the record object instead.
|
||||
let text
|
||||
if (typeof dataIndex === 'number') {
|
||||
text = get(record, dataIndex)
|
||||
} else if (!dataIndex || dataIndex.length === 0) {
|
||||
text = record
|
||||
} else {
|
||||
text = get(record, dataIndex)
|
||||
}
|
||||
let tdProps = {}
|
||||
let colSpan
|
||||
let rowSpan
|
||||
|
||||
if (render) {
|
||||
text = render(text, record, index)
|
||||
if (this.isInvalidRenderCellText(text)) {
|
||||
tdProps = text.props || tdProps
|
||||
colSpan = tdProps.colSpan
|
||||
rowSpan = tdProps.rowSpan
|
||||
text = text.children
|
||||
}
|
||||
}
|
||||
|
||||
if (column.onCell) {
|
||||
tdProps = { ...tdProps, ...column.onCell(record) }
|
||||
}
|
||||
|
||||
// Fix https://github.com/ant-design/ant-design/issues/1202
|
||||
if (this.isInvalidRenderCellText(text)) {
|
||||
text = null
|
||||
}
|
||||
|
||||
const indentText = expandIcon ? (
|
||||
<span
|
||||
style={{ paddingLeft: `${indentSize * indent}px` }}
|
||||
class={`${prefixCls}-indent indent-level-${indent}`}
|
||||
/>
|
||||
) : null
|
||||
|
||||
if (rowSpan === 0 || colSpan === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (column.align) {
|
||||
tdProps.style = { textAlign: column.align }
|
||||
}
|
||||
console.log('tdProps', tdProps)
|
||||
|
||||
return (
|
||||
<BodyCell
|
||||
onClick={this.handleClick}
|
||||
{...tdProps}
|
||||
>
|
||||
{indentText}
|
||||
{expandIcon}
|
||||
{text}
|
||||
</BodyCell>
|
||||
)
|
||||
},
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
import PropTypes from '../../_util/vue-types'
|
||||
import TableHeaderRow from './TableHeaderRow'
|
||||
|
||||
function getHeaderRows (columns, currentRow = 0, rows) {
|
||||
rows = rows || []
|
||||
rows[currentRow] = rows[currentRow] || []
|
||||
|
||||
columns.forEach(column => {
|
||||
if (column.rowSpan && rows.length < column.rowSpan) {
|
||||
while (rows.length < column.rowSpan) {
|
||||
rows.push([])
|
||||
}
|
||||
}
|
||||
const cell = {
|
||||
key: column.key,
|
||||
className: column.className || '',
|
||||
children: column.title,
|
||||
column,
|
||||
}
|
||||
if (column.children) {
|
||||
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)
|
||||
}
|
||||
})
|
||||
return rows.filter(row => row.length > 0)
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'TableHeader',
|
||||
props: {
|
||||
fixed: PropTypes.string,
|
||||
columns: PropTypes.array.isRequired,
|
||||
expander: PropTypes.object.isRequired,
|
||||
|
||||
},
|
||||
methods: {
|
||||
onHeaderRow () {
|
||||
this.table.__emit('headerRow', ...arguments)
|
||||
},
|
||||
},
|
||||
|
||||
render () {
|
||||
const { components, prefixCls, showHeader } = this.table
|
||||
const { expander, columns, fixed, onHeaderRow } = this
|
||||
|
||||
if (!showHeader) {
|
||||
return null
|
||||
}
|
||||
|
||||
const rows = getHeaderRows(columns)
|
||||
|
||||
expander.renderExpandIndentCell(rows, fixed)
|
||||
|
||||
const HeaderWrapper = components.header.wrapper
|
||||
|
||||
return (
|
||||
<HeaderWrapper class={`${prefixCls}-thead`}>
|
||||
{
|
||||
rows.map((row, index) => (
|
||||
<TableHeaderRow
|
||||
key={index}
|
||||
index={index}
|
||||
fixed={fixed}
|
||||
columns={columns}
|
||||
rows={rows}
|
||||
row={row}
|
||||
components={components}
|
||||
onHeaderRow={onHeaderRow}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</HeaderWrapper>
|
||||
)
|
||||
},
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
import React from 'react'
|
||||
import { connect } from 'mini-store'
|
||||
|
||||
function TableHeaderRow ({ row, index, height, components, onHeaderRow }) {
|
||||
const HeaderRow = components.header.row
|
||||
const HeaderCell = components.header.cell
|
||||
const rowProps = onHeaderRow(row.map(cell => cell.column), index)
|
||||
const customStyle = rowProps ? rowProps.style : {}
|
||||
const style = { height, ...customStyle }
|
||||
|
||||
return (
|
||||
<HeaderRow {...rowProps} style={style}>
|
||||
{row.map((cell, i) => {
|
||||
const { column, ...cellProps } = cell
|
||||
const customProps = column.onHeaderCell ? column.onHeaderCell(column) : {}
|
||||
if (column.align) {
|
||||
cellProps.style = { textAlign: column.align }
|
||||
}
|
||||
return (
|
||||
<HeaderCell
|
||||
{...cellProps}
|
||||
{...customProps}
|
||||
key={column.key || column.dataIndex || i}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</HeaderRow>
|
||||
)
|
||||
}
|
||||
|
||||
function getRowHeight (state, props) {
|
||||
const { fixedColumnsHeadRowsHeight } = state
|
||||
const { columns, rows, fixed } = props
|
||||
const headerHeight = fixedColumnsHeadRowsHeight[0]
|
||||
|
||||
if (!fixed) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (headerHeight && columns) {
|
||||
if (headerHeight === 'auto') {
|
||||
return 'auto'
|
||||
}
|
||||
return headerHeight / rows.length
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export default connect((state, props) => {
|
||||
return {
|
||||
height: getRowHeight(state, props),
|
||||
}
|
||||
})(TableHeaderRow)
|
|
@ -0,0 +1,291 @@
|
|||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'mini-store'
|
||||
import TableCell from './TableCell'
|
||||
import { warningOnce } from './utils'
|
||||
|
||||
class TableRow extends React.Component {
|
||||
static propTypes = {
|
||||
onRow: 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.isRequired,
|
||||
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,
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
onRow () {},
|
||||
expandIconColumnIndex: 0,
|
||||
expandRowByClick: false,
|
||||
onHover () {},
|
||||
hasExpandIcon () {},
|
||||
renderExpandIcon () {},
|
||||
renderExpandIconCell () {},
|
||||
}
|
||||
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.shouldRender = props.visible
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
if (this.shouldRender) {
|
||||
this.saveRowRef()
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
if (this.props.visible || (!this.props.visible && nextProps.visible)) {
|
||||
this.shouldRender = true
|
||||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate (nextProps) {
|
||||
return !!(this.props.visible || nextProps.visible)
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
if (this.shouldRender && !this.rowRef) {
|
||||
this.saveRowRef()
|
||||
}
|
||||
}
|
||||
|
||||
onRowClick = (event) => {
|
||||
const { record, index, onRowClick } = this.props
|
||||
if (onRowClick) {
|
||||
onRowClick(record, index, event)
|
||||
}
|
||||
}
|
||||
|
||||
onRowDoubleClick = (event) => {
|
||||
const { record, index, onRowDoubleClick } = this.props
|
||||
if (onRowDoubleClick) {
|
||||
onRowDoubleClick(record, index, event)
|
||||
}
|
||||
}
|
||||
|
||||
onContextMenu = (event) => {
|
||||
const { record, index, onRowContextMenu } = this.props
|
||||
if (onRowContextMenu) {
|
||||
onRowContextMenu(record, index, event)
|
||||
}
|
||||
}
|
||||
|
||||
onMouseEnter = (event) => {
|
||||
const { record, index, onRowMouseEnter, onHover, rowKey } = this.props
|
||||
onHover(true, rowKey)
|
||||
if (onRowMouseEnter) {
|
||||
onRowMouseEnter(record, index, event)
|
||||
}
|
||||
}
|
||||
|
||||
onMouseLeave = (event) => {
|
||||
const { record, index, onRowMouseLeave, onHover, rowKey } = this.props
|
||||
onHover(false, rowKey)
|
||||
if (onRowMouseLeave) {
|
||||
onRowMouseLeave(record, index, event)
|
||||
}
|
||||
}
|
||||
|
||||
setExpanedRowHeight () {
|
||||
const { store, rowKey } = this.props
|
||||
let { expandedRowsHeight } = store.getState()
|
||||
const height = this.rowRef.getBoundingClientRect().height
|
||||
expandedRowsHeight = {
|
||||
...expandedRowsHeight,
|
||||
[rowKey]: height,
|
||||
}
|
||||
store.setState({ expandedRowsHeight })
|
||||
}
|
||||
|
||||
setRowHeight () {
|
||||
const { store, index } = this.props
|
||||
const fixedColumnsBodyRowsHeight = store.getState().fixedColumnsBodyRowsHeight.slice()
|
||||
const height = this.rowRef.getBoundingClientRect().height
|
||||
fixedColumnsBodyRowsHeight[index] = height
|
||||
store.setState({ fixedColumnsBodyRowsHeight })
|
||||
}
|
||||
|
||||
getStyle () {
|
||||
const { height, visible } = this.props
|
||||
|
||||
if (height && height !== this.style.height) {
|
||||
this.style = { ...this.style, height }
|
||||
}
|
||||
|
||||
if (!visible && !this.style.display) {
|
||||
this.style = { ...this.style, display: 'none' }
|
||||
}
|
||||
|
||||
return this.style
|
||||
}
|
||||
|
||||
saveRowRef () {
|
||||
this.rowRef = ReactDOM.findDOMNode(this)
|
||||
|
||||
const { isAnyColumnsFixed, fixed, expandedRow, ancestorKeys } = this.props
|
||||
|
||||
if (!isAnyColumnsFixed) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!fixed && expandedRow) {
|
||||
this.setExpanedRowHeight()
|
||||
}
|
||||
|
||||
if (!fixed && ancestorKeys.length >= 0) {
|
||||
this.setRowHeight()
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
if (!this.shouldRender) {
|
||||
return null
|
||||
}
|
||||
|
||||
const {
|
||||
prefixCls,
|
||||
columns,
|
||||
record,
|
||||
index,
|
||||
onRow,
|
||||
indent,
|
||||
indentSize,
|
||||
hovered,
|
||||
height,
|
||||
visible,
|
||||
components,
|
||||
hasExpandIcon,
|
||||
renderExpandIcon,
|
||||
renderExpandIconCell,
|
||||
} = this.props
|
||||
|
||||
const BodyRow = components.body.row
|
||||
const BodyCell = components.body.cell
|
||||
|
||||
let { className } = this.props
|
||||
|
||||
if (hovered) {
|
||||
className += ` ${prefixCls}-hover`
|
||||
}
|
||||
|
||||
const cells = []
|
||||
|
||||
renderExpandIconCell(cells)
|
||||
|
||||
for (let i = 0; i < columns.length; i++) {
|
||||
const column = columns[i]
|
||||
|
||||
warningOnce(
|
||||
column.onCellClick === undefined,
|
||||
'column[onCellClick] is deprecated, please use column[onCell] 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 rowClassName =
|
||||
`${prefixCls} ${className} ${prefixCls}-level-${indent}`.trim()
|
||||
|
||||
const rowProps = onRow(record, index)
|
||||
const customStyle = rowProps ? rowProps.style : {}
|
||||
let style = { height }
|
||||
|
||||
if (!visible) {
|
||||
style.display = 'none'
|
||||
}
|
||||
|
||||
style = { ...style, ...customStyle }
|
||||
|
||||
return (
|
||||
<BodyRow
|
||||
onClick={this.onRowClick}
|
||||
onDoubleClick={this.onRowDoubleClick}
|
||||
onMouseEnter={this.onMouseEnter}
|
||||
onMouseLeave={this.onMouseLeave}
|
||||
onContextMenu={this.onContextMenu}
|
||||
className={rowClassName}
|
||||
{...rowProps}
|
||||
style={style}
|
||||
>
|
||||
{cells}
|
||||
</BodyRow>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function getRowHeight (state, props) {
|
||||
const { expandedRowsHeight, fixedColumnsBodyRowsHeight } = state
|
||||
const { fixed, index, rowKey } = props
|
||||
|
||||
if (!fixed) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (expandedRowsHeight[rowKey]) {
|
||||
return expandedRowsHeight[rowKey]
|
||||
}
|
||||
|
||||
if (fixedColumnsBodyRowsHeight[index]) {
|
||||
return fixedColumnsBodyRowsHeight[index]
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export default connect((state, props) => {
|
||||
const { currentHoverKey, expandedRowKeys } = state
|
||||
const { rowKey, ancestorKeys } = props
|
||||
const visible = ancestorKeys.length === 0 || ancestorKeys.every(k => ~expandedRowKeys.indexOf(k))
|
||||
|
||||
return ({
|
||||
visible,
|
||||
hovered: currentHoverKey === rowKey,
|
||||
height: getRowHeight(state, props),
|
||||
})
|
||||
})(TableRow)
|
|
@ -0,0 +1,84 @@
|
|||
import warning from 'warning'
|
||||
|
||||
let scrollbarSize
|
||||
|
||||
// Measure scrollbar width for padding body during modal show/hide
|
||||
const scrollbarMeasure = {
|
||||
position: 'absolute',
|
||||
top: '-9999px',
|
||||
width: '50px',
|
||||
height: '50px',
|
||||
overflow: 'scroll',
|
||||
}
|
||||
|
||||
export function measureScrollbar (direction = 'vertical') {
|
||||
if (typeof document === 'undefined' || typeof window === 'undefined') {
|
||||
return 0
|
||||
}
|
||||
if (scrollbarSize) {
|
||||
return scrollbarSize
|
||||
}
|
||||
const scrollDiv = document.createElement('div')
|
||||
for (const scrollProp in scrollbarMeasure) {
|
||||
if (scrollbarMeasure.hasOwnProperty(scrollProp)) {
|
||||
scrollDiv.style[scrollProp] = scrollbarMeasure[scrollProp]
|
||||
}
|
||||
}
|
||||
document.body.appendChild(scrollDiv)
|
||||
let size = 0
|
||||
if (direction === 'vertical') {
|
||||
size = scrollDiv.offsetWidth - scrollDiv.clientWidth
|
||||
} else if (direction === 'horizontal') {
|
||||
size = scrollDiv.offsetHeight - scrollDiv.clientHeight
|
||||
}
|
||||
|
||||
document.body.removeChild(scrollDiv)
|
||||
scrollbarSize = size
|
||||
return scrollbarSize
|
||||
}
|
||||
|
||||
export function debounce (func, wait, immediate) {
|
||||
let timeout
|
||||
function debounceFunc () {
|
||||
const context = this
|
||||
const args = arguments
|
||||
// https://fb.me/react-event-pooling
|
||||
if (args[0] && args[0].persist) {
|
||||
args[0].persist()
|
||||
}
|
||||
const later = () => {
|
||||
timeout = null
|
||||
if (!immediate) {
|
||||
func.apply(context, args)
|
||||
}
|
||||
}
|
||||
const callNow = immediate && !timeout
|
||||
clearTimeout(timeout)
|
||||
timeout = setTimeout(later, wait)
|
||||
if (callNow) {
|
||||
func.apply(context, args)
|
||||
}
|
||||
}
|
||||
debounceFunc.cancel = function cancel () {
|
||||
if (timeout) {
|
||||
clearTimeout(timeout)
|
||||
timeout = null
|
||||
}
|
||||
}
|
||||
return debounceFunc
|
||||
}
|
||||
|
||||
const warned = {}
|
||||
export function warningOnce (condition, format, args) {
|
||||
if (!warned[format]) {
|
||||
warning(condition, format, args)
|
||||
warned[format] = !condition
|
||||
}
|
||||
}
|
||||
|
||||
export function remove (array, item) {
|
||||
const index = array.indexOf(item)
|
||||
const front = array.slice(0, index)
|
||||
const last = array.slice(index + 1, array.length)
|
||||
return front.concat(last)
|
||||
}
|
Loading…
Reference in New Issue