提交 cc589654 编写于 作者: Y yiminghe

fix table

上级 5aa19b55
import React from 'react'; import React from 'react';
import Menu from 'rc-menu'; import Menu from 'rc-menu';
export default React.createClass({ var FilterMenu = React.createClass({
getInitialState() { getInitialState() {
return { return {
selectedFilters: [] selectedFilters: this.props.selectedFilters
}; };
}, },
componentWillReceiveProps(nextProps){
this.setState({
selectedFilters: nextProps.selectedFilters
});
},
getDefaultProps() { getDefaultProps() {
return { return {
handleFilter: function() {}, handleFilter: function () {
},
column: null column: null
}; };
}, },
handleSelectFilter: function(selected) { handleSelectFilter: function (selected) {
this.state.selectedFilters.push(selected);
this.setState({ this.setState({
selectedFilters: this.state.selectedFilters selectedFilters: this.state.selectedFilters.concat(selected)
}); });
}, },
handleDeselectFilter: function(key) { handleDeselectFilter: function (key) {
var index = this.state.selectedFilters.indexOf(key); var index = this.state.selectedFilters.indexOf(key);
if (index !== -1) { if (index !== -1) {
this.state.selectedFilters.splice(index, 1); var selectedFilters = this.state.selectedFilters.concat();
} selectedFilters.splice(index, 1);
this.setState({ this.setState({
selectedFilters: this.state.selectedFilters selectedFilters: selectedFilters
}); });
}
}, },
handleClearFilters() { handleClearFilters() {
this.setState({ this.setState({
selectedFilters: [] selectedFilters: []
}); });
}, },
handleConfirm(){
this.props.confirmFilter(this.props.column, this.state.selectedFilters);
},
renderMenus(items) { renderMenus(items) {
let menuItems = items.map((item) => { let menuItems = items.map((item) => {
return <Menu.Item key={item.value}>{item.text}</Menu.Item>; return <Menu.Item key={item.value}>{item.text}</Menu.Item>;
...@@ -41,13 +50,12 @@ export default React.createClass({ ...@@ -41,13 +50,12 @@ export default React.createClass({
}, },
render() { render() {
let column = this.props.column; let column = this.props.column;
column.selectedFilters = this.state.selectedFilters;
return <Menu multiple={true} return <Menu multiple={true}
prefixCls="ant-dropdown-menu" prefixCls="ant-dropdown-menu"
className="ant-table-filter-dropdown" className="ant-table-filter-dropdown"
onSelect={this.handleSelectFilter} onSelect={this.handleSelectFilter}
onDeselect={this.handleDeselectFilter} onDeselect={this.handleDeselectFilter}
selectedKeys={column.selectedFilters}> selectedKeys={this.state.selectedFilters}>
{this.renderMenus(column.filters)} {this.renderMenus(column.filters)}
<Menu.Divider /> <Menu.Divider />
<Menu.Item disabled> <Menu.Item disabled>
...@@ -56,7 +64,7 @@ export default React.createClass({ ...@@ -56,7 +64,7 @@ export default React.createClass({
cursor: 'pointer', cursor: 'pointer',
pointerEvents: 'visible' pointerEvents: 'visible'
}} }}
onClick={this.props.confirmFilter}> onClick={this.handleConfirm}>
确定 确定
</a> </a>
<a className="ant-table-filter-dropdown-link clear" <a className="ant-table-filter-dropdown-link clear"
...@@ -71,3 +79,5 @@ export default React.createClass({ ...@@ -71,3 +79,5 @@ export default React.createClass({
</Menu>; </Menu>;
} }
}); });
export default FilterMenu;
...@@ -6,22 +6,33 @@ import Checkbox from '../checkbox'; ...@@ -6,22 +6,33 @@ import Checkbox from '../checkbox';
import FilterMenu from './filterMenu'; import FilterMenu from './filterMenu';
import Pagination from '../pagination'; import Pagination from '../pagination';
import objectAssign from 'object-assign'; import objectAssign from 'object-assign';
import equals from 'is-equal-shallow';
export default React.createClass({ function noop() {
getInitialState() { }
this.initDataSource(this.props.dataSource);
let noPagination = (this.props.pagination === false); function defaultResolve(data) {
let pagination = this.initPagination(this.props.pagination); return data || [];
}
export default React.createClass({
getInitialState() {
return { return {
// 减少状态
selectedRowKeys: [], selectedRowKeys: [],
loading: false, // only for remote
pagination: pagination, data: [],
noPagination: noPagination, filters: {},
data: [] loading: !this.isLocalDataSource(),
sortColumn: '',
sortOrder: '',
sorter: null,
pagination: this.hasPagination() ? objectAssign({
pageSize: 10
}, this.props.pagination) : {}
}; };
}, },
getDefaultProps() { getDefaultProps() {
return { return {
prefixCls: 'ant-table', prefixCls: 'ant-table',
...@@ -30,43 +41,42 @@ export default React.createClass({ ...@@ -30,43 +41,42 @@ export default React.createClass({
size: 'normal' size: 'normal'
}; };
}, },
componentWillReceiveProps(nextProps) {
if ('pagination' in nextProps) { componentWillReceiveProps(nextProps){
let noPagination = (nextProps.pagination === false); if (('pagination' in nextProps) && nextProps.pagination !== false) {
this.setState({ this.setState({
pagination: this.initPagination(nextProps.pagination), pagination: objectAssign({}, this.state.pagination, nextProps.pagination)
noPagination: noPagination
}); });
} }
if ('dataSource' in nextProps) { if (!this.isLocalDataSource()) {
this.initDataSource(nextProps.dataSource); if (!equals(nextProps, this.props)) {
this.setState({ this.setState({
data: nextProps.dataSource selectedRowKeys: [],
loading: true
}, this.fetch);
}
}
if (nextProps.columns !== this.props.columns) {
this.setState({
filters: {}
}); });
} }
}, },
initDataSource(dataSource) { hasPagination(pagination){
// 支持两种模式 if (pagination === undefined) {
if (Array.isArray(dataSource)) { pagination = this.props.pagination;
this.mode = 'local';
// 保留原来的数据
this.originDataSource = dataSource.slice(0);
} else {
this.mode = 'remote';
this.dataSource = objectAssign({
resolve: function(data) {
return data || [];
},
getParams: function() {},
getPagination: function() {}
}, dataSource);
} }
return pagination !== false;
},
isLocalDataSource(){
return Array.isArray(this.props.dataSource);
}, },
initPagination(pagination) { getRemoteDataSource(){
return objectAssign({ return objectAssign({
pageSize: 10, resolve: defaultResolve,
total: this.props.dataSource.length getParams: noop,
}, pagination); getPagination: noop
}, this.props.dataSource);
}, },
toggleSortOrder(order, column) { toggleSortOrder(order, column) {
let sortColumn = this.state.sortColumn; let sortColumn = this.state.sortColumn;
...@@ -89,8 +99,8 @@ export default React.createClass({ ...@@ -89,8 +99,8 @@ export default React.createClass({
sortColumn.className = 'ant-table-column-sort'; sortColumn.className = 'ant-table-column-sort';
} }
} }
if (this.mode === 'local') { if (this.isLocalDataSource()) {
sorter = function() { sorter = function () {
let result = column.sorter.apply(this, arguments); let result = column.sorter.apply(this, arguments);
if (sortOrder === 'ascend') { if (sortOrder === 'ascend') {
return result; return result;
...@@ -99,87 +109,94 @@ export default React.createClass({ ...@@ -99,87 +109,94 @@ export default React.createClass({
} }
}; };
} }
this.setState({ this.fetch({
sortOrder: sortOrder, sortOrder: sortOrder,
sortColumn: sortColumn, sortColumn: sortColumn,
sorter: sorter sorter: sorter
}, this.fetch); });
}, },
handleFilter(column) { handleFilter(column, filters) {
let columnIndex = this.props.columns.indexOf(column); filters = objectAssign({}, this.state.filters, {
let filterFns = []; [this.getColumnKey(column)]: filters
if (this.mode === 'local') { });
filterFns[columnIndex] = function(record) { this.fetch({
if (column.selectedFilters.length === 0) { selectedRowKeys: [],
return true; filters: filters
}
return column.selectedFilters.some(function(value) {
return column.onFilter.call(this, value, record);
}); });
};
}
this.setState({
filterFns: filterFns
}, this.fetch);
}, },
handleSelect(rowIndex, e) { handleSelect(record, rowIndex, e) {
let checked = e.target.checked; let checked = e.target.checked;
let selectedRowKeys = this.state.selectedRowKeys.concat();
let key = this.getRecordKey(record, rowIndex);
if (checked) { if (checked) {
this.state.selectedRowKeys.push(rowIndex); selectedRowKeys.push(this.getRecordKey(record, rowIndex));
} else { } else {
this.state.selectedRowKeys = this.state.selectedRowKeys.filter(function(i) { selectedRowKeys = selectedRowKeys.filter((i) => {
return rowIndex !== i; return key !== i;
}); });
} }
this.setState({ this.setState({
selectedRowKeys: this.state.selectedRowKeys selectedRowKeys: selectedRowKeys
}); });
if (this.props.rowSelection.onSelect) { if (this.props.rowSelection.onSelect) {
let currentRow = this.state.data[rowIndex - 1]; let data = this.getCurrentPageData();
let selectedRows = this.state.data.filter((row, i) => { let selectedRows = data.filter((row, i) => {
return this.state.selectedRowKeys.indexOf(i + 1) >= 0; return selectedRowKeys.indexOf(this.getRecordKey(row, i)) >= 0;
}); });
this.props.rowSelection.onSelect(currentRow, checked, selectedRows); this.props.rowSelection.onSelect(record, checked, selectedRows);
} }
}, },
handleSelectAllRow(e) { handleSelectAllRow(e) {
let checked = e.target.checked; let checked = e.target.checked;
let selectedRowKeys = checked ? this.state.data.map(function(item, i) { let data = this.getCurrentPageData();
return i + 1; let selectedRowKeys = checked ? data.map((item, i) => {
return this.getRecordKey(item, i);
}) : []; }) : [];
this.setState({ this.setState({
selectedRowKeys: selectedRowKeys selectedRowKeys: selectedRowKeys
}); });
if (this.props.rowSelection.onSelectAll) { if (this.props.rowSelection.onSelectAll) {
let selectedRows = this.state.data.filter((row, i) => { let selectedRows = data.filter((row, i) => {
return selectedRowKeys.indexOf(i + 1) >= 0; return selectedRowKeys.indexOf(this.getRecordKey(row, i)) >= 0;
}); });
this.props.rowSelection.onSelectAll(checked, selectedRows); this.props.rowSelection.onSelectAll(checked, selectedRows);
} }
}, },
handlePageChange(current) { handlePageChange(current) {
let pagination = this.state.pagination || {}; let pagination = objectAssign({}, this.state.pagination);
if (current) { if (current) {
pagination.current = current; pagination.current = current;
} else { } else {
pagination.current = pagination.current || 1; pagination.current = pagination.current || 1;
} }
this.setState({ this.fetch({
// 防止内存泄漏,只维持当页
selectedRowKeys: [],
pagination: pagination pagination: pagination
}, this.fetch); });
}, },
renderSelectionCheckBox(value, record, index) { renderSelectionCheckBox(value, record, index) {
let rowIndex = index + 1; // 从 1 开始 let rowIndex = this.getRecordKey(record, index); // 从 1 开始
let checked = this.state.selectedRowKeys.indexOf(rowIndex) >= 0; let checked = this.state.selectedRowKeys.indexOf(rowIndex) >= 0;
return <Checkbox checked={checked} onChange={this.handleSelect.bind(this, rowIndex)} />; return <Checkbox checked={checked} onChange={this.handleSelect.bind(this, record, rowIndex)}/>;
},
getRecordKey(record, index){
return record.key || index;
}, },
renderRowSelection() { renderRowSelection() {
var columns = this.props.columns; let columns = this.props.columns.concat();
if (this.props.rowSelection) { if (this.props.rowSelection) {
let checked = this.state.data.every(function(item, i) { let data = this.getCurrentPageData();
return this.state.selectedRowKeys.indexOf(i + 1) >= 0; let checked;
}, this); if (!data.length) {
let checkboxAll = <Checkbox checked={checked} onChange={this.handleSelectAllRow} />; checked = false;
} else {
checked = data.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 = { let selectionColumn = {
key: 'selection-column', key: 'selection-column',
title: checkboxAll, title: checkboxAll,
...@@ -196,17 +213,27 @@ export default React.createClass({ ...@@ -196,17 +213,27 @@ export default React.createClass({
} }
return columns; return columns;
}, },
renderColumnsDropdown() {
return this.props.columns.map((column) => { getCurrentPageData(){
if (!column.originTitle) { return this.isLocalDataSource() ? this.getLocalDataPaging() : this.state.data;
column.originTitle = column.title; },
}
getColumnKey(column){
return column.key || column.dataIndex;
},
renderColumnsDropdown(columns) {
return columns.map((column) => {
column = objectAssign({}, column);
let key = this.getColumnKey(column);
let filterDropdown, menus, sortButton; let filterDropdown, menus, sortButton;
if (column.filters && column.filters.length > 0) { if (column.filters && column.filters.length > 0) {
column.selectedFilters = column.selectedFilters || []; let colFilters = this.state.filters[key] || [];
menus = <FilterMenu column={column} confirmFilter={this.handleFilter.bind(this, column)} />; menus = <FilterMenu column={column}
selectedFilters={colFilters}
confirmFilter={this.handleFilter}/>;
let dropdownSelectedClass = ''; let dropdownSelectedClass = '';
if (column.selectedFilters && column.selectedFilters.length > 0) { if (colFilters.length > 0) {
dropdownSelectedClass = 'ant-table-filter-selected'; dropdownSelectedClass = 'ant-table-filter-selected';
} }
filterDropdown = <Dropdown trigger="click" filterDropdown = <Dropdown trigger="click"
...@@ -232,8 +259,9 @@ export default React.createClass({ ...@@ -232,8 +259,9 @@ export default React.createClass({
</span> </span>
</div>; </div>;
} }
let originalTitle = column.title;
column.title = [ column.title = [
column.originTitle, originalTitle,
sortButton, sortButton,
filterDropdown filterDropdown
]; ];
...@@ -242,129 +270,165 @@ export default React.createClass({ ...@@ -242,129 +270,165 @@ export default React.createClass({
}, },
renderPagination() { renderPagination() {
// 强制不需要分页 // 强制不需要分页
if (this.state.noPagination) { if (!this.hasPagination()) {
return ''; return null;
} }
let classString = 'ant-table-pagination'; let classString = 'ant-table-pagination';
if (this.props.size === 'small') { if (this.props.size === 'small') {
classString += ' mini'; classString += ' mini';
} }
let total;
if (this.isLocalDataSource()) {
total = this.getLocalData().length;
}
return <Pagination className={classString} return <Pagination className={classString}
onChange={this.handlePageChange} onChange={this.handlePageChange}
total={total}
pageSize={10}
{...this.state.pagination} />; {...this.state.pagination} />;
}, },
prepareParamsArguments() { prepareParamsArguments(state) {
// 准备筛选、排序、分页的参数 // 准备筛选、排序、分页的参数
let pagination; let pagination;
let filters = {}; let filters = {};
let sorter = {}; let sorter = {};
pagination = this.state.pagination; pagination = state.pagination;
this.props.columns.forEach(function(column) { this.props.columns.forEach((column) => {
if (column.dataIndex && column.selectedFilters && let colFilters = state.filters[this.getColumnKey(column)] || [];
column.selectedFilters.length > 0) { if (colFilters.length > 0) {
filters[column.dataIndex] = column.selectedFilters; filters[this.getColumnKey(column)] = colFilters;
} }
}); });
if (this.state.sortColumn && this.state.sortOrder && if (state.sortColumn &&
this.state.sortColumn.dataIndex) { state.sortOrder &&
sorter.field = this.state.sortColumn.dataIndex; state.sortColumn.dataIndex) {
sorter.order = this.state.sortOrder; sorter.field = state.sortColumn.dataIndex;
sorter.order = state.sortOrder;
} }
return [pagination, filters, sorter]; return [pagination, filters, sorter];
}, },
fetch() {
if (this.mode === 'remote') { fetch(newState) {
// remote 模式使用 this.dataSource if (this.isLocalDataSource()) {
let dataSource = this.dataSource; if (newState) {
this.setState({ this.setState(newState);
}
} else {
let state = objectAssign({}, this.state, newState);
if (newState || !this.state.loading) {
this.setState(objectAssign({
loading: true loading: true
}); }, newState));
}
// remote 模式使用 this.dataSource
let dataSource = this.getRemoteDataSource();
jQuery.ajax({ jQuery.ajax({
url: dataSource.url, url: dataSource.url,
data: dataSource.getParams.apply(this, this.prepareParamsArguments()) || {}, data: dataSource.getParams.apply(this, this.prepareParamsArguments(state)) || {},
headers: dataSource.headers, headers: dataSource.headers,
dataType: 'json', dataType: 'json',
success: (result) => { success: (result) => {
if (this.isMounted()) { if (this.isMounted()) {
let pagination = objectAssign( let pagination = objectAssign(
this.state.pagination, state.pagination,
dataSource.getPagination.call(this, result) dataSource.getPagination.call(this, result)
); );
this.setState({ this.setState({
loading: false,
data: dataSource.resolve.call(this, result), data: dataSource.resolve.call(this, result),
pagination: pagination, pagination: pagination
loading: false
}); });
} }
}, },
error: () => { error: () => {
this.setState({ this.setState({
loading: false loading: false,
data: []
}); });
} }
}); });
} else { }
let data = this.props.dataSource; },
findColumn(myKey){
return this.props.columns.filter((c) => {
return this.getColumnKey(c) === myKey;
})[0];
},
getLocalDataPaging(){
let data = this.getLocalData();
let current, pageSize; let current, pageSize;
let state = this.state;
// 如果没有分页的话,默认全部展示 // 如果没有分页的话,默认全部展示
if (this.state.noPagination) { if (!this.hasPagination()) {
pageSize = Number.MAX_VALUE; pageSize = Number.MAX_VALUE;
current = 1; current = 1;
} else { } else {
pageSize = this.state.pagination.pageSize; pageSize = state.pagination.pageSize;
current = this.state.pagination.current; current = state.pagination.current;
}
// 排序
if (this.state.sortOrder && this.state.sorter) {
data = data.sort(this.state.sorter);
} else {
data = this.originDataSource.slice();
}
// 筛选
if (this.state.filterFns) {
this.state.filterFns.forEach(function(filterFn) {
if (typeof filterFn === 'function') {
data = data.filter(filterFn);
}
});
} }
// 分页 // 分页
// --- // ---
// 当数据量少于每页数量时,直接设置数据 // 当数据量少于每页数量时,直接设置数据
// 否则进行读取分页数据 // 否则进行读取分页数据
if (data.length > pageSize || pageSize === Number.MAX_VALUE) { if (data.length > pageSize || pageSize === Number.MAX_VALUE) {
data = data.filter(function(item, i) { data = data.filter((item, i) => {
if (i >= (current - 1) * pageSize && if (i >= (current - 1) * pageSize &&
i < current * pageSize) { i < current * pageSize) {
return item; return item;
} }
}); });
} }
// 完成数据 return data;
this.setState({ },
data: data
getLocalData(){
let state = this.state;
let data = this.props.dataSource;
// 排序
if (state.sortOrder && state.sorter) {
data = data.sort(state.sorter);
}
// 筛选
if (state.filters) {
Object.keys(state.filters).forEach((columnKey) => {
let col = this.findColumn(columnKey);
let values = state.filters[columnKey] || [];
data = data.filter((record) => {
return values.some((v)=> {
return col.onFilter(v, record);
});
});
}); });
} }
return data;
}, },
componentDidMount() { componentDidMount() {
this.handlePageChange(); if (!this.isLocalDataSource()) {
this.fetch();
}
}, },
render() {
this.props.columns = this.renderRowSelection();
var classString = ''; render() {
if (this.state.loading) { let data = this.getCurrentPageData();
let columns = this.renderRowSelection();
let classString = '';
if (this.state.loading && this.isLocalDataSource()) {
classString += ' ant-table-loading'; classString += ' ant-table-loading';
} }
if (this.props.size === 'small') { if (this.props.size === 'small') {
classString += ' ant-table-small'; classString += ' ant-table-small';
} }
columns = this.renderColumnsDropdown(columns);
return <div className="clearfix"> return <div className="clearfix">
<Table data={this.state.data} <Table
columns={this.renderColumnsDropdown()} {...this.props}
data={data || []}
columns={columns}
className={classString} className={classString}
{...this.props} /> />
{this.renderPagination()} {this.renderPagination()}
</div>; </div>;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册