Table 列选择模式重构

+ 表格 `rowSelection` 支持多选
+ 表格可配置某行数据默认选中、不能选中。该配置对 ajax 载入的数据有效。
示例:
```
getCheckboxProps: function (value) {
    return {
        defaultValue: value.name === '胡彦祖ajax2', // 配置默认勾选的列
        disabled: value.name === '李大嘴ajax3'    // 配置无法勾选的列
    }
},
```
This commit is contained in:
RaoHai 2015-10-09 17:14:09 +08:00
parent c98c3eef57
commit 2c1fda70d6
14 changed files with 403 additions and 23 deletions

View File

@ -0,0 +1,117 @@
# 配置动态加载数据
- order: 7
远程读取的表格是**更为常见的模式**,下面的表格使用了 `dataSource` 对象和远程数据源绑定和适配,并具有筛选、排序等功能以及页面 loading 效果。
**注意,此示例是静态数据模拟,数据并不准确,请打开网络面板查看请求。**
---
````jsx
var Table = antd.Table;
var columns = [{
title: '姓名',
dataIndex: 'name',
filters: [{
text: '姓李的',
value: '李'
}, {
text: '姓胡的',
value: '胡'
}]
}, {
title: '年龄',
dataIndex: 'age',
sorter: true
}, {
title: '住址',
dataIndex: 'address'
}];
var dataSource = new Table.DataSource({
url: "/components/table/demo/data.json",
resolve: function(result) {
return result.data;
},
data: {},
// 和后台接口返回的分页数据进行适配
getPagination: function(result) {
return {
total: result.totalCount,
pageSize: result.pageSize
}
},
// 和后台接口接收的参数进行适配
// 参数里提供了分页、筛选、排序的信息
getParams: function(pagination, filters, sorter) {
console.log('getParams 的参数是:', pagination, filters, sorter);
var params = {
pageSize: pagination.pageSize,
currentPage: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order
};
for (var key in filters) {
params[key] = filters[key];
}
console.log('请求参数:', params);
return params;
}
});
var rowSelection = {
getCheckboxProps: function (value) {
return {
defaultValue: value.name === '胡彦祖ajax2', // 配置默认勾选的列
disabled: value.name === '李大嘴ajax3' // 配置无法勾选的列
}
},
onSelect: function(record, selected, selectedRows) {
console.log(record, selected, selectedRows);
},
onSelectAll: function(selected, selectedRows) {
console.log(selected, selectedRows);
}
};
var Test = React.createClass({
getInitialState() {
return {
dataSource: dataSource
};
},
refresh() {
this.setState({
dataSource: dataSource.clone()
});
},
changeAndRefresh() {
// 可以修改原来的 dataSource 再发请求
this.setState({
dataSource: dataSource.clone({
data: {
city: 'hz'
}
})
});
},
render() {
return <div>
<Table rowSelection={rowSelection} columns={columns} dataSource={this.state.dataSource} />
<button className="ant-btn ant-btn-primary" onClick={this.refresh}>
重新加载数据
</button>
&nbsp;
<button className="ant-btn" onClick={this.changeAndRefresh}>
加载 city=hz 的数据
</button>
</div>;
}
});
React.render(<Test />, document.getElementById('components-table-demo-ajax-props'));
````

View File

@ -1,6 +1,6 @@
# 动态加载数据
- order: 4
- order: 7
远程读取的表格是**更为常见的模式**,下面的表格使用了 `dataSource` 对象和远程数据源绑定和适配,并具有筛选、排序等功能以及页面 loading 效果。

View File

@ -1,6 +1,6 @@
# 边框
- order: 7
- order: 10
添加表格边框线,`bordered={true}`。

View File

@ -1,6 +1,6 @@
# 可展开
- order: 9
- order: 12
当表格内容较多不能一次性完全展示时。

View File

@ -1,6 +1,6 @@
# 筛选和排序
- order: 3
- order: 6
对某一列数据进行筛选,使用列的 `filter` 属性来指定筛选的列表。

View File

@ -1,6 +1,6 @@
# 外界控制数据
- order: 8
- order: 11
由父元素控制自身数据展示。

View File

@ -1,6 +1,6 @@
# 不显示分页
- order: 5
- order: 8
传入 pagination 为 false 即可。

View File

@ -1,6 +1,6 @@
# 分页
- order: 2
- order: 5
数据项较多时显示分页。

View File

@ -0,0 +1,59 @@
# 配置
- order: 2
配置选择框的默认属性。
---
````jsx
var Table = antd.Table;
var columns = [{
title: '姓名',
dataIndex: 'name',
render: function(text) {
return <a href="javascript:;">{text}</a>;
}
}, {
title: '年龄',
dataIndex: 'age'
}, {
title: '住址',
dataIndex: 'address'
}];
var data = [{
key: '1',
name: '胡彦斌',
age: 32,
address: '西湖区湖底公园1号'
}, {
key: '2',
name: '胡彦祖',
age: 42,
address: '西湖区湖底公园1号'
}, {
key: '3',
name: '李大嘴',
age: 32,
address: '西湖区湖底公园1号'
}];
// 通过 rowSelection 对象表明需要行选择
var rowSelection = {
getCheckboxProps: function (value) {
return {
defaultValue: value.name === '李大嘴', // 配置默认勾选的列
disabled: value.name === '胡彦祖' // 配置无法勾选的列
}
},
onSelect: function(record, selected, selectedRows) {
console.log(record, selected, selectedRows);
},
onSelectAll: function(selected, selectedRows) {
console.log(selected, selectedRows);
}
};
React.render(<Table rowSelection={rowSelection} columns={columns} dataSource={data} />
, document.getElementById('components-table-demo-row-selection-props'));
````

View File

@ -0,0 +1,60 @@
# 单选配置
- order: 4
配置单选框的默认属性。
---
````jsx
var Table = antd.Table;
var columns = [{
title: '姓名',
dataIndex: 'name',
render: function(text) {
return <a href="javascript:;">{text}</a>;
}
}, {
title: '年龄',
dataIndex: 'age'
}, {
title: '住址',
dataIndex: 'address'
}];
var data = [{
key: '1',
name: '胡彦斌',
age: 32,
address: '西湖区湖底公园1号'
}, {
key: '2',
name: '胡彦祖',
age: 42,
address: '西湖区湖底公园1号'
}, {
key: '3',
name: '李大嘴',
age: 32,
address: '西湖区湖底公园1号'
}];
// 通过 rowSelection 对象表明需要行选择
var rowSelection = {
type: 'radio',
getCheckboxProps: function (value) {
return {
defaultValue: value.name === '李大嘴', // 配置默认勾选的列
disabled: value.name === '胡彦祖' // 配置无法勾选的列
}
},
onSelect: function(record, selected, selectedRows) {
console.log(record, selected, selectedRows);
},
onSelectAll: function(selected, selectedRows) {
console.log(selected, selectedRows);
}
};
React.render(<Table rowSelection={rowSelection} columns={columns} dataSource={data} />
, document.getElementById('components-table-demo-row-selection-radio-props'));
````

View File

@ -0,0 +1,54 @@
# 单选
- order: 3
第一列是联动的单选框。
---
````jsx
var Table = antd.Table;
var columns = [{
title: '姓名',
dataIndex: 'name',
render: function(text) {
return <a href="javascript:;">{text}</a>;
}
}, {
title: '年龄',
dataIndex: 'age'
}, {
title: '住址',
dataIndex: 'address'
}];
var data = [{
key: '1',
name: '胡彦斌',
age: 32,
address: '西湖区湖底公园1号'
}, {
key: '2',
name: '胡彦祖',
age: 42,
address: '西湖区湖底公园1号'
}, {
key: '3',
name: '李大嘴',
age: 32,
address: '西湖区湖底公园1号'
}];
// 通过 rowSelection 对象表明需要行选择
var rowSelection = {
type: 'radio',
onSelect: function(record, selected, selectedRows) {
console.log(record, selected, selectedRows);
},
onSelectAll: function(selected, selectedRows) {
console.log(selected, selectedRows);
}
};
React.render(<Table rowSelection={rowSelection} columns={columns} dataSource={data} />
, document.getElementById('components-table-demo-row-selection-radio'));
````

View File

@ -1,6 +1,6 @@
# 小型列表
- order: 6
- order: 9
`size="small"`, 用在对话框等空间较小的地方。

View File

@ -2,6 +2,7 @@ import React from 'react';
import reqwest from 'reqwest-without-xhr2';
import Table from 'rc-table';
import Checkbox from '../checkbox';
import Radio from '../radio';
import FilterDropdown from './filterDropdown';
import Pagination from '../pagination';
import objectAssign from 'object-assign';
@ -44,10 +45,12 @@ let AntTable = React.createClass({
data: [],
dataSource: this.props.dataSource,
filters: {},
dirty: false,
loading: false,
sortColumn: '',
sortOrder: '',
sorter: null,
radioIndex: null,
pagination: this.hasPagination() ? objectAssign({
pageSize: 10,
current: 1
@ -69,6 +72,22 @@ let AntTable = React.createClass({
dataSource: React.PropTypes.oneOfType([React.PropTypes.array, React.PropTypes.instanceOf(DataSource)])
},
getDefaultSelection() {
let selectedRowKeys = [];
if (this.props.rowSelection && this.props.rowSelection.getCheckboxProps) {
let data = this.getCurrentPageData();
data.filter((item) => {
if (this.props.rowSelection.getCheckboxProps) {
return this.props.rowSelection.getCheckboxProps(item).defaultValue;
}
return true;
}).map((record, rowIndex) => {
selectedRowKeys.push(this.getRecordKey(record, rowIndex));
});
}
return selectedRowKeys;
},
componentWillReceiveProps(nextProps) {
if (('pagination' in nextProps) && nextProps.pagination !== false) {
this.setState({
@ -152,7 +171,11 @@ let AntTable = React.createClass({
handleSelect(record, rowIndex, e) {
let checked = e.target.checked;
let selectedRowKeys = this.state.selectedRowKeys.concat();
let defaultSelection = [];
if (!this.state.dirty) {
defaultSelection = this.getDefaultSelection();
}
let selectedRowKeys = this.state.selectedRowKeys.concat(defaultSelection);
let key = this.getRecordKey(record, rowIndex);
if (checked) {
selectedRowKeys.push(this.getRecordKey(record, rowIndex));
@ -162,7 +185,31 @@ let AntTable = React.createClass({
});
}
this.setState({
selectedRowKeys: selectedRowKeys
selectedRowKeys: selectedRowKeys,
dirty: true
});
if (this.props.rowSelection.onSelect) {
let data = this.getCurrentPageData();
let selectedRows = data.filter((row, i) => {
return selectedRowKeys.indexOf(this.getRecordKey(row, i)) >= 0;
});
this.props.rowSelection.onSelect(record, checked, selectedRows);
}
},
handleRadioSelect: function (record, rowIndex, e) {
let checked = e.target.checked;
let defaultSelection = [];
if (!this.state.dirty) {
defaultSelection = this.getDefaultSelection();
}
let selectedRowKeys = this.state.selectedRowKeys.concat(defaultSelection);
let key = this.getRecordKey(record, rowIndex);
selectedRowKeys = [key];
this.setState({
selectedRowKeys: selectedRowKeys,
radioIndex: record.key,
dirty: true
});
if (this.props.rowSelection.onSelect) {
let data = this.getCurrentPageData();
@ -176,11 +223,17 @@ let AntTable = React.createClass({
handleSelectAllRow(e) {
let checked = e.target.checked;
let data = this.getCurrentPageData();
let selectedRowKeys = checked ? data.map((item, i) => {
let selectedRowKeys = checked ? data.filter((item) => {
if (this.props.rowSelection.getCheckboxProps) {
return !this.props.rowSelection.getCheckboxProps(item).disabled;
}
return true;
}).map((item, i) => {
return this.getRecordKey(item, i);
}) : [];
this.setState({
selectedRowKeys: selectedRowKeys
selectedRowKeys: selectedRowKeys,
dirty: true
});
if (this.props.rowSelection.onSelectAll) {
let selectedRows = data.filter((row, i) => {
@ -204,10 +257,30 @@ let AntTable = React.createClass({
});
},
onRadioChange: function (ev) {
this.setState({
radioIndex: ev.target.value
});
},
renderSelectionRadio(value, record, index) {
let rowIndex = this.getRecordKey(record, index); // 1
let props = {};
if (this.props.rowSelection.getCheckboxProps) {
props = this.props.rowSelection.getCheckboxProps.call(this, record);
}
const checked = this.state.dirty ? this.state.radioIndex === record.key : this.getDefaultSelection().indexOf(rowIndex) >= 0;
return <Radio disabled={props.disabled} onChange={this.handleRadioSelect.bind(this, record, rowIndex)} value={record.key} checked={checked} />;
},
renderSelectionCheckBox(value, record, index) {
let rowIndex = this.getRecordKey(record, index); // 1
let checked = this.state.selectedRowKeys.indexOf(rowIndex) >= 0;
return <Checkbox checked={checked} onChange={this.handleSelect.bind(this, record, rowIndex)}/>;
let checked = this.state.dirty ? this.state.selectedRowKeys.indexOf(rowIndex) >= 0 : this.getDefaultSelection().indexOf(rowIndex) >= 0;
let props = {};
if (this.props.rowSelection.getCheckboxProps) {
props = this.props.rowSelection.getCheckboxProps.call(this, record);
}
return <Checkbox checked={checked} disabled={props.disabled} onChange={this.handleSelect.bind(this, record, rowIndex)}/>;
},
getRecordKey(record, index) {
@ -222,19 +295,34 @@ let AntTable = React.createClass({
if (!data.length) {
checked = false;
} else {
checked = data.every((item, i) => {
checked = data.filter((item) => {
if (this.props.rowSelection.getCheckboxProps) {
return !this.props.rowSelection.getCheckboxProps(item).disabled;
}
return true;
}).every((item, i) => {
let key = this.getRecordKey(item, i);
return this.state.selectedRowKeys.indexOf(key) >= 0;
});
}
let checkboxAll = <Checkbox checked={checked} onChange={this.handleSelectAllRow}/>;
let selectionColumn = {
key: 'selection-column',
title: checkboxAll,
width: 60,
render: this.renderSelectionCheckBox,
className: 'ant-table-selection-column'
};
let selectionColumn;
if (this.props.rowSelection.type === 'radio') {
selectionColumn = {
key: 'selection-column',
width: 60,
render: this.renderSelectionRadio,
className: 'ant-table-selection-column'
};
} else {
let checkboxAll = <Checkbox checked={checked} onChange={this.handleSelectAllRow}/>;
selectionColumn = {
key: 'selection-column',
title: checkboxAll,
width: 60,
render: this.renderSelectionCheckBox,
className: 'ant-table-selection-column'
};
}
if (columns[0] &&
columns[0].key === 'selection-column') {
columns[0] = selectionColumn;
@ -383,6 +471,7 @@ let AntTable = React.createClass({
dataSource.getPagination.call(this, result)
);
this.setState({
dirty: false,
loading: false,
data: dataSource.resolve.call(this, result),
pagination: pagination

View File

@ -32,6 +32,7 @@
],
"license": "MIT",
"dependencies": {
"react": "~0.13.3",
"css-animation": "~1.1.0",
"enter-animation": "~0.5.0",
"gregorian-calendar": "~3.0.0",