截止目前最新的Ext-4.2.1.883版本,分别提供日期组件(xtype:'datefield')和时间组件(xtype:'timefield'),却没有提供日期+时分秒组件。
搜索到的牛人扩展组件代码贴下:
1、新建时间选择器上的时分秒输入框类TimePickerField.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
|
/**
* 时间输入框, 三个整数框分别输入时,分,秒.
* @author wangzilong
* update Ext - 4.1 2012/04/27
*/
Ext.define(
'MyApp.ux.TimePickerField'
, {
extend:
'Ext.form.field.Base'
,
alias:
'widget.timepicker'
,
alternateClassName:
'Ext.form.field.TimePickerField'
,
requires: [
'Ext.form.field.Number'
],
// 隐藏BaseField的输入框 , hidden basefield's input
inputType: 'hidden
',
style: '
padding:4px 0 0 0;margin-bottom:0px
',
/**
* @cfg {String} value
* initValue, format: '
H:i:s
'
*/
value: null,
/**
* @cfg {Object} spinnerCfg
* 数字输入框参数, number input config
*/
spinnerCfg: {
width: 40
},
/** Override. */
initComponent: function() {
var me = this;
me.value = me.value || Ext.Date.format(new Date(), '
H:i:s
');
me.callParent();// called setValue
me.spinners = [];
var cfg = Ext.apply({}, me.spinnerCfg, {
readOnly: me.readOnly,
disabled: me.disabled,
style: '
float: left
',
listeners: {
change: {
fn: me.onSpinnerChange,
scope: me
}
}
});
me.hoursSpinner = Ext.create('
Ext.form.field.Number
', Ext.apply({}, cfg, {
minValue: 0,
maxValue: 23
}));
me.minutesSpinner = Ext.create('
Ext.form.field.Number
', Ext.apply({}, cfg, {
minValue: 0,
maxValue: 59
}));
// TODO 使用timeformat 判断是否创建秒输入框, maybe second field is not always need.
me.secondsSpinner = Ext.create('
Ext.form.field.Number
', Ext.apply({}, cfg, {
minValue: 0,
maxValue: 59
}));
me.spinners.push(me.hoursSpinner, me.minutesSpinner, me.secondsSpinner);
},
/**
* @private
* Override.
*/
onRender: function() {
var me = this, spinnerWrapDom, spinnerWrap;
me.callParent(arguments);
// render to original BaseField input td
// spinnerWrap = Ext.get(Ext.DomQuery.selectNode('
div
', this.el.dom)); // 4.0.2
spinnerWrapDom = Ext.dom.Query.select('
td
', this.getEl().dom)[1]; // 4.0 ->4.1 div->td
spinnerWrap = Ext.get(spinnerWrapDom);
me.callSpinnersFunction('
render
', spinnerWrap);
Ext.core.DomHelper.append(spinnerWrap, {
tag: '
div
',
cls: '
x-form-clear-left
'
});
this.setRawValue(this.value);
},
_valueSplit: function(v) {
if(Ext.isDate(v)) {
v = Ext.Date.format(v, '
H:i:s
');
}
var split = v.split('
:
');
return {
h: split.length > 0 ? split[0] : 0,
m: split.length > 1 ? split[1] : 0,
s: split.length > 2 ? split[2] : 0
};
},
onSpinnerChange: function() {
if(!this.rendered) {
return;
}
this.fireEvent('
change
', this, this.getValue(), this.getRawValue());
},
// 依次调用各输入框函数, call each spinner'
s
function
callSpinnersFunction:
function
(funName, args) {
for
(
var
i = 0; i <
this
.spinners.length; i++) {
this
.spinners[i][funName](args);
}
},
// @private get time as object,
getRawValue:
function
() {
if
(!
this
.rendered) {
var
date =
this
.value ||
new
Date();
return
this
._valueSplit(date);
}
else
{
return
{
h:
this
.hoursSpinner.getValue(),
m:
this
.minutesSpinner.getValue(),
s:
this
.secondsSpinner.getValue()
};
}
},
// private
setRawValue:
function
(value) {
value =
this
._valueSplit(value);
if
(
this
.hoursSpinner) {
this
.hoursSpinner.setValue(value.h);
this
.minutesSpinner.setValue(value.m);
this
.secondsSpinner.setValue(value.s);
}
},
// overwrite
getValue:
function
() {
var
v =
this
.getRawValue();
return
Ext.String.leftPad(v.h, 2,
'0'
) +
':'
+ Ext.String.leftPad(v.m, 2,
'0'
) +
':'
+ Ext.String.leftPad(v.s, 2,
'0'
);
},
// overwrite
setValue:
function
(value) {
this
.value = Ext.isDate(value) ? Ext.Date.format(value,
'H:i:s'
) : value;
if
(!
this
.rendered) {
return
;
}
this
.setRawValue(
this
.value);
this
.validate();
},
// overwrite
disable:
function
() {
this
.callParent(arguments);
this
.callSpinnersFunction(
'disable'
, arguments);
},
// overwrite
enable:
function
() {
this
.callParent(arguments);
this
.callSpinnersFunction(
'enable'
, arguments);
},
// overwrite
setReadOnly:
function
() {
this
.callParent(arguments);
this
.callSpinnersFunction(
'setReadOnly'
, arguments);
},
// overwrite
clearInvalid:
function
() {
this
.callParent(arguments);
this
.callSpinnersFunction(
'clearInvalid'
, arguments);
},
// overwrite
isValid:
function
(preventMark) {
return
this
.hoursSpinner.isValid(preventMark) &&
this
.minutesSpinner.isValid(preventMark)
&&
this
.secondsSpinner.isValid(preventMark);
},
// overwrite
validate:
function
() {
return
this
.hoursSpinner.validate() &&
this
.minutesSpinner.validate() &&
this
.secondsSpinner.validate();
}
});
|
2、将日期选择器datepicker组件扩展成日期时分秒选择器datetimepicker:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
Ext.define(
'MyApp.ux.DateTimePicker'
, {
extend:
'Ext.picker.Date'
,
alias:
'widget.datetimepicker'
,
todayText:
'现在'
,
timeLabel:
'时间'
,
requires: [
'MyApp.ux.TimePickerField'
],
initComponent:
function
() {
// keep time part for value
var
value =
this
.value ||
new
Date();
this
.callParent();
this
.value = value;
},
onRender:
function
(container, position) {
if
(!
this
.timefield) {
this
.timefield = Ext.create(
'MyApp.ux.TimePickerField'
, {
fieldLabel:
this
.timeLabel,
labelWidth: 40,
value: Ext.Date.format(
this
.value,
'H:i:s'
)
});
}
this
.timefield.ownerCt =
this
;
this
.timefield.on(
'change'
,
this
.timeChange,
this
);
this
.callParent(arguments);
var
table = Ext.get(Ext.DomQuery.selectNode(
'table'
,
this
.el.dom));
var
tfEl = Ext.core.DomHelper.insertAfter(table, {
tag:
'div'
,
style:
'border:0px;'
,
children: [{
tag:
'div'
,
cls:
'x-datepicker-footer ux-timefield'
}]
},
true
);
this
.timefield.render(
this
.el.child(
'div div.ux-timefield'
));
var
p =
this
.getEl().parent(
'div.x-layer'
);
if
(p) {
p.setStyle(
"height"
, p.getHeight() + 31);
}
},
// listener 时间域修改, timefield change
timeChange:
function
(tf, time, rawtime) {
// if(!this.todayKeyListener) { // before render
this
.value =
this
.fillDateTime(
this
.value);
// } else {
// this.setValue(this.value);
// }
},
// @private
fillDateTime:
function
(value) {
if
(
this
.timefield) {
var
rawtime =
this
.timefield.getRawValue();
value.setHours(rawtime.h);
value.setMinutes(rawtime.m);
value.setSeconds(rawtime.s);
}
return
value;
},
// @private
changeTimeFiledValue:
function
(value) {
this
.timefield.un(
'change'
,
this
.timeChange,
this
);
this
.timefield.setValue(
this
.value);
this
.timefield.on(
'change'
,
this
.timeChange,
this
);
},
/* TODO 时间值与输入框绑定, 考虑: 创建this.timeValue 将日期和时间分开保存. */
// overwrite
setValue:
function
(value) {
this
.value = value;
this
.changeTimeFiledValue(value);
return
this
.update(
this
.value);
},
// overwrite
getValue:
function
() {
return
this
.fillDateTime(
this
.value);
},
// overwrite : fill time before setValue
handleDateClick:
function
(e, t) {
var
me =
this
,
handler = me.handler;
e.stopEvent();
if
(!me.disabled && t.dateValue && !Ext.fly(t.parentNode).hasCls(me.disabledCellCls)) {
me.doCancelFocus = me.focusOnSelect ===
false
;
me.setValue(
this
.fillDateTime(
new
Date(t.dateValue)));
// overwrite: fill time before setValue
delete
me.doCancelFocus;
me.fireEvent(
'select'
, me, me.value);
if
(handler) {
handler.call(me.scope || me, me, me.value);
}
me.onSelect();
}
},
// overwrite : fill time before setValue
selectToday:
function
() {
var
me =
this
,
btn = me.todayBtn,
handler = me.handler;
if
(btn && !btn.disabled) {
// me.setValue(Ext.Date.clearTime(new Date())); //src
me.setValue(
new
Date());
// overwrite: fill time before setValue
me.fireEvent(
'select'
, me, me.value);
if
(handler) {
handler.call(me.scope || me, me, me.value);
}
me.onSelect();
}
return
me;
}
});
|
2、引用日期时分秒选择器datetimepicker,将日期datefield组件扩展成日期时分秒datetimefield组件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
Ext.Loader.setConfig({enabled:
true
});
Ext.Loader.setPath(
'MyApp'
,
'../houtai/js'
);
Ext.define(
'MyApp.ux.DateTimeField'
, {
extend:
'Ext.form.field.Date'
,
alias:
'widget.datetimefield'
,
requires: [
'MyApp.ux.DateTimePicker'
],
initComponent:
function
() {
this
.format =
this
.format;
this
.callParent();
},
// overwrite
createPicker:
function
() {
var
me =
this
,
format = Ext.String.format;
return
Ext.create(
'MyApp.ux.DateTimePicker'
, {
ownerCt: me.ownerCt,
renderTo: document.body,
floating:
true
,
hidden:
true
,
focusOnShow:
true
,
minDate: me.minValue,
maxDate: me.maxValue,
disabledDatesRE: me.disabledDatesRE,
disabledDatesText: me.disabledDatesText,
disabledDays: me.disabledDays,
disabledDaysText: me.disabledDaysText,
format: me.format,
showToday: me.showToday,
startDay: me.startDay,
minText: format(me.minText, me.formatDate(me.minValue)),
maxText: format(me.maxText, me.formatDate(me.maxValue)),
listeners: {
scope: me,
select: me.onSelect
},
keyNavConfig: {
esc:
function
() {
me.collapse();
}
}
});
}
});
|
3、在form中使用xtype:datetimefield,首先引入扩展类:
1
|
requires:
'MyApp.ux.DateTimeField'
,
|
具体使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
{
xtype:
'datetimefield'
,
width : 300,
labelWidth : 80,
endDateField:
'etime'
,
vtype:
'daterange'
,
fieldLabel:
'记录时间下限'
,
format:
'Y-m-d H:i:s '
,
name:
'stime'
},
{
xtype:
'datetimefield'
,
width : 300,
labelWidth : 80,
startDateField:
'stime'
,
vtype:
'daterange'
,
fieldLabel:
'记录时间上限'
,
format:
'Y-m-d H:i:s '
,
name:
'etime'
},
|
4、页面效果:
5、使用体验:
可实现日期时分秒的选择输入,但操作体验略差强人意。如:选择器上只有'现在'按钮,若增加‘确定’按钮,点击后选择器消失,日期时分秒值填入框体就好了。现在选非'现在'的精确时间,最后需以点击日期结束,框体中的年月日时分秒才与选择器中完全一致。