Skip to content

Commit d2c3372

Browse files
✨ [feature] Add characteristics of automatic configuration Year, Month, Day, Hour, Minute, Second.
1 parent 89e1b78 commit d2c3372

File tree

8 files changed

+202
-47
lines changed

8 files changed

+202
-47
lines changed

examples/basic/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ window.Perf = require('react-addons-perf');
6161
</a>
6262
</div>
6363
<DatePicker
64+
dateFormat={['hh', 'mm', 'ss']}
65+
showFormat="hh时:mm分:ss秒"
6466
value={this.state.time}
6567
theme={this.state.theme}
6668
isOpen={this.state.isOpen}

lib/DatePicker.js

+12-23
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class DatePicker extends Component {
6565
* @return {Object} JSX对象
6666
*/
6767
render() {
68-
const { min, max, theme, dateFormat, confirmText, cancelText } = this.props;
68+
const { min, max, theme, dateFormat, confirmText, cancelText, showFormat } = this.props;
6969
const value = this.state.value;
7070
const themeClassName =
7171
['default', 'dark', 'ios', 'android', 'android-dark'].indexOf(theme) === -1 ?
@@ -74,29 +74,17 @@ class DatePicker extends Component {
7474
return (
7575
<div
7676
className={`datepicker ${themeClassName}`}>
77-
<div className="datepicker-header">{convertDate(value, 'YYYY/MM/DD')}</div>
77+
<div className="datepicker-header">{convertDate(value, showFormat)}</div>
7878
<div className="datepicker-content">
79-
<DatePickerItem
80-
value={value}
81-
min={min}
82-
max={max}
83-
typeName="Year"
84-
format={dateFormat[0]}
85-
onSelect={this.handleDateSelect} />
86-
<DatePickerItem
87-
value={value}
88-
min={min}
89-
max={max}
90-
typeName="Month"
91-
format={dateFormat[1]}
92-
onSelect={this.handleDateSelect} />
93-
<DatePickerItem
94-
value={value}
95-
min={min}
96-
max={max}
97-
typeName="Date"
98-
format={dateFormat[2]}
99-
onSelect={this.handleDateSelect} />
79+
{dateFormat.map((format, index) => (
80+
<DatePickerItem
81+
key={index}
82+
value={value}
83+
min={min}
84+
max={max}
85+
format={format}
86+
onSelect={this.handleDateSelect} />
87+
))}
10088
</div>
10189
<div className="datepicker-navbar">
10290
<a
@@ -117,6 +105,7 @@ DatePicker.propTypes = {
117105
min: PropTypes.object,
118106
max: PropTypes.object,
119107
dateFormat: PropTypes.array,
108+
showFormat: PropTypes.string,
120109
confirmText: PropTypes.string,
121110
cancelText: PropTypes.string,
122111
onSelect: PropTypes.func,

lib/DatePickerItem.js

+31-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,33 @@ const MIDDLE_Y = - DATE_HEIGHT * MIDDLE_INDEX; // translateY值
1414

1515
const isUndefined = val => typeof val === 'undefined';
1616

17+
/**
18+
* 根据格式获取时间滑动的类别
19+
* @param {String} format 格式
20+
* @return {string} 类别名称
21+
*/
22+
const getTimeType = format => {
23+
const typeMap = {
24+
Y: 'Year',
25+
M: 'Month',
26+
D: 'Date',
27+
h: 'Hour',
28+
m: 'Minute',
29+
s: 'Second',
30+
};
31+
32+
for (const key in typeMap) {
33+
if (typeMap.hasOwnProperty(key)) {
34+
if (~format.indexOf(key)) {
35+
return typeMap[key]
36+
}
37+
}
38+
}
39+
40+
throw new Error('时间格式必须包含 Y, M, D, h, m 或 s字母');
41+
}
42+
43+
1744
/**
1845
* Class Date组件类
1946
* @extends Component
@@ -31,6 +58,8 @@ class DatePickerItem extends Component {
3158
marginTop: (this.currentIndex - MIDDLE_INDEX) * DATE_HEIGHT,
3259
};
3360

61+
// 设置时间选择器单元的类别
62+
this.typeName = getTimeType(props.format);
3463
this.renderDatepickerItem = this.renderDatepickerItem.bind(this);
3564
this.handleContentTouch = this.handleContentTouch.bind(this);
3665
this.handleContentMouseDown = this.handleContentMouseDown.bind(this);
@@ -84,15 +113,15 @@ class DatePickerItem extends Component {
84113
}
85114

86115
_iniDates(date) {
87-
const { typeName } = this.props;
116+
const typeName = this.typeName;
88117
const dates = Array(...Array(DATE_LENGTH))
89118
.map((value, index) =>
90119
TimeUtil[`next${typeName}`](date, index - MIDDLE_INDEX));
91120
this.setState({ dates });
92121
}
93122

94123
_updateDates(direction) {
95-
const { typeName } = this.props;
124+
const typeName = this.typeName;
96125
const { dates } = this.state;
97126
if (direction === 1) {
98127
this.currentIndex ++;
@@ -305,7 +334,6 @@ DatePickerItem.propTypes = {
305334
min: PropTypes.object,
306335
max: PropTypes.object,
307336
format: PropTypes.string,
308-
typeName: PropTypes.string,
309337
onSelect: PropTypes.func,
310338
};
311339

lib/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ ModalDatePicker.defaultProps = {
5656
min: new Date(1970, 0, 1),
5757
max: new Date(2050, 0, 1),
5858
dateFormat: ['YYYY', 'M', 'D'],
59+
showFormat: 'YYYY/MM/DD',
5960
confirmText: '完成',
6061
cancelText: '取消',
6162
onSelect: () => {},

lib/time.js

+42-10
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
* @module time工具
33
*/
44

5-
65
function throwIfInvalidDate(date) {
76
if (Object.prototype.toString.call(date, null) !== '[object Date]') {
87
throw new Error('参数类型不对');
@@ -28,15 +27,16 @@ export function convertDate(date, format) {
2827
's+': date.getSeconds(),
2928
};
3029
if (/(Y+)/.test(format)) {
31-
str = str.replace(RegExp.$1,
32-
(date.getFullYear().toString()).substr(4 - RegExp.$1.length));
30+
str = str.replace(RegExp.$1, date.getFullYear().toString().substr(4 - RegExp.$1.length));
3331
}
3432

35-
for (const k in o) { // eslint-disable-line
33+
for (const k in o) {
34+
// eslint-disable-line
3635
if (new RegExp(`(${k})`).test(format)) {
37-
str = str.replace(RegExp.$1,
38-
(RegExp.$1.length === 1) ?
39-
o[k] : (`00${o[k]}`.substr((o[k].toString()).length)));
36+
str = str.replace(
37+
RegExp.$1,
38+
RegExp.$1.length === 1 ? o[k] : `00${o[k]}`.substr(o[k].toString().length),
39+
);
4040
}
4141
}
4242

@@ -50,7 +50,14 @@ export function convertDate(date, format) {
5050
*/
5151
export function nextYear(now, index = 0) {
5252
throwIfInvalidDate(now);
53-
const date = new Date(now.getFullYear() + index, now.getMonth(), now.getDate());
53+
const date = new Date(
54+
now.getFullYear() + index,
55+
now.getMonth(),
56+
now.getDate(),
57+
now.getHours(),
58+
now.getMinutes(),
59+
now.getSeconds(),
60+
);
5461
return date;
5562
}
5663

@@ -59,12 +66,37 @@ export function nextMonth(now, index = 0) {
5966
const year = now.getFullYear();
6067
const month = now.getMonth() + index;
6168
const dayOfMonth = Math.min(now.getDate(), daysInMonth(year, month));
62-
const date = new Date(year, month, dayOfMonth);
69+
const date = new Date(
70+
year,
71+
month,
72+
dayOfMonth,
73+
now.getHours(),
74+
now.getMinutes(),
75+
now.getSeconds(),
76+
);
6377
return date;
6478
}
6579

6680
export function nextDate(now, index = 0) {
6781
throwIfInvalidDate(now);
68-
const date = new Date(now.getFullYear(), now.getMonth(), now.getDate() + index);
82+
const date = new Date(now.getTime() + index * 24 * 60 * 60 * 1000);
83+
return date;
84+
}
85+
86+
export function nextHour(now, index = 0) {
87+
throwIfInvalidDate(now);
88+
const date = new Date(now.getTime() + index * 60 * 60 * 1000);
89+
return date;
90+
}
91+
92+
export function nextMinute(now, index = 0) {
93+
throwIfInvalidDate(now);
94+
const date = new Date(now.getTime() + index * 60 * 1000);
95+
return date;
96+
}
97+
98+
export function nextSecond(now, index = 0) {
99+
throwIfInvalidDate(now);
100+
const date = new Date(now.getTime() + index * 1000);
69101
return date;
70102
}

test/functional/DatePickerItem_spec.js

+8-9
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ const DEFAULT_PROPS = {
1111
value: new Date(2010, 3, 7),
1212
min: new Date(2010, 2, 6),
1313
max: new Date(2010, 4, 8),
14-
format: 'M',
1514
onSelect: () => {},
1615
}
1716

@@ -20,7 +19,7 @@ describe('DatePickerItem.js', () => {
2019
it('should call componentWillMount and initialize dates of state', () => {
2120
const spyFunction = sinon.spy(DatePickerItem.prototype, 'componentWillMount');
2221
const datePicker = mount(
23-
<DatePickerItem {...DEFAULT_PROPS} typeName="Date" />
22+
<DatePickerItem {...DEFAULT_PROPS} format="D" />
2423
);
2524
const dates = datePicker.state('dates');
2625
sinon.assert.calledOnce(spyFunction);
@@ -35,7 +34,7 @@ describe('DatePickerItem.js', () => {
3534
it('componentWillReceiveProps', () => {
3635
const spyFunction = sinon.spy(DatePickerItem.prototype, 'componentWillReceiveProps');
3736
const datePicker = mount(
38-
<DatePickerItem {...DEFAULT_PROPS} typeName="Date" />
37+
<DatePickerItem {...DEFAULT_PROPS} format="D" />
3938
);
4039
datePicker.setProps({ date: new Date(2010, 3, 10) });
4140
const dates = datePicker.state('dates');
@@ -51,7 +50,7 @@ describe('DatePickerItem.js', () => {
5150
it('shouldComponentUpdate', () => {
5251
const spyFunction = sinon.spy(DatePickerItem.prototype, 'shouldComponentUpdate');
5352
const datePicker = mount(
54-
<DatePickerItem {...DEFAULT_PROPS} typeName="Date" />
53+
<DatePickerItem {...DEFAULT_PROPS} format="D" />
5554
);
5655

5756
datePicker.setProps({ value: new Date(2010, 3, 10) });
@@ -65,7 +64,7 @@ describe('DatePickerItem.js', () => {
6564
it('should call handleContent three times after touching', () => {
6665
const spyFunction = sinon.spy(DatePickerItem.prototype, 'handleContentTouch');
6766
const datePicker = mount(
68-
<DatePickerItem {...DEFAULT_PROPS} typeName="Date" />
67+
<DatePickerItem {...DEFAULT_PROPS} format="D" />
6968
);
7069

7170
const touchstartEvent = {
@@ -93,7 +92,7 @@ describe('DatePickerItem.js', () => {
9392
it('should analyzing the right direction', () => {
9493
const spyFunction = sinon.spy(DatePickerItem.prototype, '_moveToNext');
9594
const datePicker = mount(
96-
<DatePickerItem {...DEFAULT_PROPS} typeName="Date" />
95+
<DatePickerItem {...DEFAULT_PROPS} format="D" />
9796
);
9897
const touchstartEvent = {
9998
targetTouches: [{ pageY: 0 }],
@@ -110,7 +109,7 @@ describe('DatePickerItem.js', () => {
110109
expect(spyFunction.getCall(0).args[0]).to.equal(-1);
111110

112111
const datePicker2 = mount(
113-
<DatePickerItem {...DEFAULT_PROPS} typeName="Date" />
112+
<DatePickerItem {...DEFAULT_PROPS} format="D" />
114113
);
115114
const touchstartEvent2 = {
116115
targetTouches: [{ pageY: 0 }],
@@ -132,7 +131,7 @@ describe('DatePickerItem.js', () => {
132131
it('should update dates of state, When the sliding more than 20', () => {
133132
const spyFunction = sinon.spy(DatePickerItem.prototype, '_updateDates');
134133
const datePicker = mount(
135-
<DatePickerItem {...DEFAULT_PROPS} typeName="Date" />
134+
<DatePickerItem {...DEFAULT_PROPS} format="D" />
136135
);
137136
const touchstartEvent = {
138137
targetTouches: [{ pageY: 0 }],
@@ -161,7 +160,7 @@ describe('DatePickerItem.js', () => {
161160

162161
const spyFunction = sinon.spy(DatePickerItem.prototype, '_moveTo');
163162
const datePicker = mount(
164-
<DatePickerItem {...props} typeName="Date" />
163+
<DatePickerItem {...props} format="D" />
165164
);
166165

167166
const touchstartEvent = {

test/functional/DatePicker_spec.js

+52
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,55 @@ describe('DatePicker.js', () => {
265265
})
266266
});
267267
});
268+
269+
describe('渲染正确的DatepicketItem子组件', () => {
270+
let props;
271+
let mountedDatepicker;
272+
273+
const datePicker = () => {
274+
if (!mountedDatepicker) {
275+
mountedDatepicker = mount(
276+
<DatePicker {...props} />
277+
);
278+
}
279+
280+
return mountedDatepicker;
281+
}
282+
283+
beforeEach(() => {
284+
props = {
285+
value: new Date(2016, 8, 16),
286+
};
287+
mountedDatepicker = undefined;
288+
});
289+
290+
it('当dateFormat等于[YYYY, MM, DD]', () => {
291+
props.dateFormat = ['YYYY', 'MM', 'DD'];
292+
const datePickerItems = datePicker().find(DatePickerItem);
293+
expect(datePickerItems.length).to.equals(3);
294+
expect(datePickerItems.at(0).props().format).to.equals('YYYY');
295+
expect(datePickerItems.at(1).props().format).to.equals('MM');
296+
expect(datePickerItems.at(2).props().format).to.equals('DD');
297+
});
298+
299+
it('当dateFormat等于[YYYY, MM, DD, hh, mm, ss]', () => {
300+
props.dateFormat = ['YYYY', 'MM', 'DD', 'hh', 'mm', 'ss'];
301+
const datePickerItems = datePicker().find(DatePickerItem);
302+
expect(datePickerItems.length).to.equals(6);
303+
expect(datePickerItems.at(0).props().format).to.equals('YYYY');
304+
expect(datePickerItems.at(1).props().format).to.equals('MM');
305+
expect(datePickerItems.at(2).props().format).to.equals('DD');
306+
expect(datePickerItems.at(3).props().format).to.equals('hh');
307+
expect(datePickerItems.at(4).props().format).to.equals('mm');
308+
expect(datePickerItems.at(5).props().format).to.equals('ss');
309+
});
310+
311+
it('当dateFormat等于[hh, mm, ss]', () => {
312+
props.dateFormat = ['hh', 'mm', 'ss'];
313+
const datePickerItems = datePicker().find(DatePickerItem);
314+
expect(datePickerItems.length).to.equals(3);
315+
expect(datePickerItems.at(0).props().format).to.equals('hh');
316+
expect(datePickerItems.at(1).props().format).to.equals('mm');
317+
expect(datePickerItems.at(2).props().format).to.equals('ss');
318+
});
319+
});

0 commit comments

Comments
 (0)