Skip to content

Commit 2451eb2

Browse files
committed
table sort
1 parent 2e88449 commit 2451eb2

File tree

8 files changed

+185
-98
lines changed

8 files changed

+185
-98
lines changed

docs/src/js/pages/formItem.jsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
'use strict';
22

3-
import { Component } from 'react';
43
import Code from '../Code';
54
import Example from '../Example';
65
const { Form, FormControl, FormItem } = global.uiRequire();
@@ -24,7 +23,7 @@ module.exports = () => {
2423
<div>可以直接当作Component,把自定义组件当作children传入。一个FormItem只能接受一个自定义组件,并且这个组件必须实现一个<em>onChange(value)</em>事件返回值,接受<em>value</em>作为props传入值</div>
2524
<Code>
2625
{`<FormItem
27-
className="string", // 需要额外添加的 className
26+
className="string" // 需要额外添加的 className
2827
name={string} // 数据key名称,唯一
2928
type={string} // 自动验证以下type: email,integer,number,alpha,alphanum,tel,url
3029
min={int} // 值类型为 string 时,最小长度;为 number 时,最小值;为 array 时,最少选项数

docs/src/js/pages/table.jsx

+19-7
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ headers = [{
6363
content:{string|func} // 表格显示内容,{}格式字符串模板或一个返回ReactElement的方法
6464
hidden:{bool} // 是否显示,默认为true
6565
name:{string} // 必填,字段名称,和data对应,如果不填content,使用name获取数据
66-
sortAble:{bool} // 是否可以排序,默认值为false
66+
sort:{bool} // 是否可以排序,默认值为false
6767
width:{number} // 宽度
6868
header:{string|element} // 表头内容,string或者ReactElement
6969
}]
@@ -158,19 +158,31 @@ headers = [{
158158
width={this.state.width}
159159
height={this.state.height}
160160
fetch={this.state.fetch}
161-
headers={[
162-
{ name: 'name', sortAble: true, header: 'Name',
161+
columns={[
162+
{ name: 'name', sort: true, header: 'Name',
163163
content: (d) => {
164164
return <a onClick={() => { Modal.alert('点击了:' + d.name); }}>{d.name}</a>;
165165
}
166166
},
167167
{ name: 'position', hidden: true },
168-
{ name: 'office', sortAble: true, header: 'Office' },
169-
{ name: 'start_date', sortAble: true, content: '{start_date}', header: 'Start Date' },
170-
{ name: 'salary', content: '{salary}', header: 'Salary' },
168+
{ name: 'office', sort: true, header: 'Office' },
169+
{ name: 'start_date', content: '{start_date}', header: 'Start Date', sort: [
170+
(a, b) => a.start_date > b.start_date ? 1 : -1,
171+
(a, b) => a.start_date < b.start_date ? 1 : -1
172+
] },
173+
{ name: 'salary', content: '{salary}', header: 'Salary', sort: (a, b) => {
174+
return parseInt(a.salary.replace(/[\$,]/g, '')) >
175+
parseInt(b.salary.replace(/[\$,]/g, '')) ? 1 : -1;
176+
} },
171177
{ name: 'tools', width: 60,
172178
content: (d) => {
173-
return <a onClick={() => { Modal.confirm('确定要删除' + d.name + '吗', () => { console.log('just a kidding.'); }); }}>删除</a>;
179+
return (
180+
<a onClick={() => {
181+
Modal.confirm('确定要删除' + d.name + '吗', () => {
182+
console.log('just a kidding.');
183+
});
184+
}}>删除</a>
185+
);
174186
}
175187
}
176188
]}

src/Form.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,9 @@ class Form extends Component {
138138
// send clone data
139139
let data = clone(this.state.data);
140140

141-
// remove ignore value
141+
// remove disabled value
142142
forEach(this.items, (item) => {
143-
if (item.ignore) {
143+
if (item.disabled) {
144144
delete data[item.name];
145145
}
146146
});

src/Table/Header.js

+32-36
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,53 @@
11
'use strict';
22

3-
import React, { Component } from 'react';
43
import classnames from 'classnames';
54
import PropTypes from '../utils/proptypes';
65

7-
export default class Header extends Component {
8-
constructor (props) {
9-
super(props);
10-
this.state = {
11-
asc: 0
12-
};
13-
this.onSort = this.onSort.bind(this);
14-
}
6+
import _tables from '../styles/_tables.scss';
157

16-
onSort () {
17-
let asc = this.state.asc === 0 ? 1 : 0;
18-
this.setState({ asc });
19-
this.props.onSort(this.props.name, asc);
20-
}
8+
function getClassName (base, name, asc, status) {
9+
return classnames(
10+
base,
11+
name === status.key && asc === status.asc && _tables.active
12+
);
13+
}
14+
15+
export default function Header (props) {
16+
const { onSort, sortStatus, name, sort, header, children } = props;
2117

22-
render () {
23-
let sort = [];
24-
let onSort = null;
25-
let style = {};
26-
27-
if (this.props.sortAble) {
28-
sort.push(<i key="up" className={classnames('arrow-up', {active: this.props.name === this.props.sort.name && this.state.asc === 1})} />);
29-
sort.push(<i key="down" className={classnames('arrow-down', {active: this.props.name === this.props.sort.name && this.state.asc === 0})} />);
30-
31-
onSort = this.onSort;
32-
style = { cursor: 'pointer' };
33-
}
34-
35-
return (
36-
<th style={style} onClick={onSort}>
37-
{this.props.header}
38-
{sort}
39-
</th>
40-
);
18+
const handleSort = (asc, fn) => {
19+
if (name === sortStatus.key && asc === sortStatus.asc) return;
20+
return () => onSort(name, asc, fn);
21+
};
22+
23+
let icons;
24+
25+
if (sort === true || Array.isArray(sort)) {
26+
let fns = sort === true ? [] : sort;
27+
icons = [
28+
<a key="up" onClick={handleSort(0, fns[0])} className={getClassName(_tables['sort-up'], name, 0, sortStatus)} />,
29+
<a key="down" onClick={handleSort(1, fns[1])} className={getClassName(_tables['sort-down'], name, 1, sortStatus)} />
30+
];
31+
} else if (typeof sort === 'function') {
32+
icons = <a onClick={handleSort(0, sort)} className={getClassName(_tables['sort-one'], name, 0, sortStatus)} />;
4133
}
34+
35+
return <th>{header}{children}{icons}</th>;
4236
}
4337

4438
Header.propTypes = {
39+
children: PropTypes.any,
4540
content: PropTypes.any,
4641
header: PropTypes.any,
4742
hidden: PropTypes.bool,
4843
name: PropTypes.string,
4944
onSort: PropTypes.func,
50-
sort: PropTypes.object,
51-
sortAble: PropTypes.bool,
45+
sort: PropTypes.bool_func,
46+
sortStatus: PropTypes.object,
5247
width: PropTypes.number_string
5348
};
5449

5550
Header.defaultProps = {
56-
hidden: false
51+
hidden: false,
52+
sortStatus: {}
5753
};

src/Table/Table.js

+23-30
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,6 @@ import _tables from '../styles/_tables.scss';
1414
export default class Table extends Component {
1515
constructor (props) {
1616
super(props);
17-
this.state = {
18-
sort: {}
19-
};
20-
2117
this.onBodyScroll = this.onBodyScroll.bind(this);
2218
}
2319

@@ -54,7 +50,6 @@ export default class Table extends Component {
5450
if (!tr) return;
5551

5652
let ths = this.refs.header.querySelectorAll('th');
57-
5853
let tds = tr.querySelectorAll('td');
5954

6055
if (tds.length <= 1) return;
@@ -66,16 +61,6 @@ export default class Table extends Component {
6661
}
6762
}
6863

69-
getSelected (name) {
70-
let values = [];
71-
this.state.data.forEach((d) => {
72-
if (d.$checked) {
73-
values.push(name ? d[name] : d);
74-
}
75-
});
76-
return values;
77-
}
78-
7964
onBodyScroll (e) {
8065
let hc = this.refs.headerContainer;
8166
hc.style.marginLeft = (0 - e.target.scrollLeft) + 'px';
@@ -86,13 +71,14 @@ export default class Table extends Component {
8671
}
8772

8873
renderBody (data) {
89-
const { selectAble, headers } = this.props;
74+
const { selectAble } = this.props;
75+
const columns = this.getColumns();
9076

9177
if (!Array.isArray(data)) {
92-
return <tbody><tr><td colSpan={headers.length}>{data}</td></tr></tbody>;
78+
return <tbody><tr><td colSpan={columns.length}>{data}</td></tr></tbody>;
9379
}
9480

95-
const headerKeys = headers.map((h) => {
81+
const headerKeys = columns.map((h) => {
9682
return h.name || hashcode(h);
9783
});
9884

@@ -106,7 +92,7 @@ export default class Table extends Component {
10692
);
10793
}
10894
let rowKey = d.id ? d.id : hashcode(d);
109-
headers.map((h, j) => {
95+
columns.map((h, j) => {
11096
if (h.hidden) {
11197
return;
11298
}
@@ -127,17 +113,21 @@ export default class Table extends Component {
127113
}
128114

129115
renderColgroup () {
130-
const { selectAble, headers } = this.props;
116+
const { selectAble } = this.props;
131117
let cols = [];
132118
if (selectAble) {
133119
cols.push(<col key="check" />);
134120
}
135-
headers.forEach((h, i) => {
121+
this.getColumns().forEach((h, i) => {
136122
cols.push(<col key={i} style={h.width ? { width: h.width } : undefined} />);
137123
});
138124
return <colgroup>{cols}</colgroup>;
139125
}
140126

127+
getColumns () {
128+
return this.props.columns || this.props.headers();
129+
}
130+
141131
renderHeader () {
142132
let headers = [];
143133
if (this.props.selectAble) {
@@ -147,19 +137,20 @@ export default class Table extends Component {
147137
} />
148138
);
149139
}
150-
this.props.headers.map((header, i) => {
140+
141+
const { onSort, sortStatus } = this.props;
142+
143+
this.getColumns().forEach((header, i) => {
151144
if (header.hidden) {
152145
return;
153146
}
154147

155-
let props = {
156-
key: header.name || i,
157-
onSort: this.props.onSort,
158-
sort: this.state.sort
159-
};
160-
161148
headers.push(
162-
<Header {...header} {...props} />
149+
<Header {...header}
150+
key={header.name || i}
151+
onSort={onSort}
152+
sortStatus={sortStatus}
153+
/>
163154
);
164155
});
165156
return <tr>{headers}</tr>;
@@ -170,7 +161,7 @@ export default class Table extends Component {
170161
if (!pagination) return;
171162

172163
return (
173-
<div className={_tables[`pagi_${pagination.position}`]}>
164+
<div className={_tables[`pagi-${pagination.position}`]}>
174165
<Pagination {...pagination} />
175166
</div>
176167
);
@@ -236,13 +227,15 @@ Table.propTypes = {
236227
bordered: PropTypes.bool,
237228
children: PropTypes.array,
238229
className: PropTypes.string,
230+
columns: PropTypes.array,
239231
data: PropTypes.array,
240232
filters: PropTypes.array,
241233
headers: PropTypes.array,
242234
height: PropTypes.number_string,
243235
onSort: PropTypes.func,
244236
pagination: PropTypes.object,
245237
selectAble: PropTypes.bool,
238+
sortStatus: PropTypes.object,
246239
striped: PropTypes.bool,
247240
style: PropTypes.object,
248241
width: PropTypes.number_string

src/higherOrders/FormItem.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ export const valueble = (ComposedComponent) => {
8787
}
8888

8989
bindToForm (props, value) {
90-
const { name, validator, ignore, itemBind } = props;
90+
const { name, validator, disabled, ignore, itemBind } = props;
9191
this.id = nextUid();
9292
let valiBind;
9393
if (validator && validator.bind) {
@@ -101,7 +101,7 @@ export const valueble = (ComposedComponent) => {
101101
id: this.id,
102102
name,
103103
valiBind,
104-
ignore,
104+
disabled: disabled || ignore,
105105
value,
106106
validate: this.validate.bind(this)
107107
});
@@ -183,6 +183,7 @@ export const valueble = (ComposedComponent) => {
183183

184184
FormItem.propTypes = {
185185
className: PropTypes.string,
186+
disabled: PropTypes.bool,
186187
formData: PropTypes.object,
187188
ignore: PropTypes.bool,
188189
itemBind: PropTypes.func,

src/higherOrders/Sort.js

+24-17
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22

33
import React from 'react';
44
import PropTypes from '../utils/proptypes';
5+
import { isEmpty } from '../utils/objects';
6+
7+
const defaultSort = (key, asc) => (a, b) => {
8+
let x = a[key];
9+
let y = b[key];
10+
if (asc === 0) {
11+
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
12+
} else {
13+
return ((x > y) ? -1 : ((x < y) ? 1 : 0));
14+
}
15+
};
516

617
export function sortable (Component) {
718
class Sort extends React.Component {
@@ -12,30 +23,26 @@ export function sortable (Component) {
1223
this.handleSort = this.handleSort.bind(this);
1324
}
1425

15-
handleSort (key, asc) {
16-
this.setState({ key, asc });
26+
handleSort (key, asc, fn) {
27+
this.setState({ key, asc, fn });
1728
this.props.onSort && this.props.onSort(key, asc);
1829
}
1930

20-
sort (data, key, asc) {
21-
return data.sort(function (a, b) {
22-
var x = a[key];
23-
var y = b[key];
24-
if (asc) {
25-
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
26-
} else {
27-
return ((x > y) ? -1 : ((x < y) ? 1 : 0));
28-
}
29-
});
31+
sort (data, { key, asc, fn }) {
32+
return data.sort(typeof fn === 'function' ? fn : defaultSort(key, asc));
3033
}
3134

3235
render () {
33-
const { key, asc } = this.state;
36+
const state = this.state;
3437
const { data, ...props } = this.props;
35-
36-
let sortData = key ? this.sort(data, key, asc) : data;
37-
38-
return <Component {...props} onSort={this.handleSort} data={sortData} />;
38+
let sortData = isEmpty(state) ? data : this.sort(data, state);
39+
40+
return (
41+
<Component {...props}
42+
onSort={this.handleSort}
43+
sortStatus={{ key: state.key, asc: state.asc }}
44+
data={sortData} />
45+
);
3946
}
4047
}
4148

0 commit comments

Comments
 (0)