截止目前最新的Ext-4.2.1.883版本,分别提供日期组件(xtype:'datefield')和时间组件(xtype:'timefield'),却没有提供日期+时分秒组件。
搜索到的牛人扩展组件代码贴下:
1、新建时间选择器上的时分秒输入框类TimePickerField.js
/** * 时间输入框, 三个整数框分别输入时,分,秒. * @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:
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组件:
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,首先引入扩展类:
requires:'MyApp.ux.DateTimeField',
具体使用:
{ 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、使用体验:
可实现日期时分秒的选择输入,但操作体验略差强人意。如:选择器上只有'现在'按钮,若增加‘确定’按钮,点击后选择器消失,日期时分秒值填入框体就好了。现在选非'现在'的精确时间,最后需以点击日期结束,框体中的年月日时分秒才与选择器中完全一致。