常规功能和模块自定义系统 (cfcmms)—055 extjs6的DateTimeField

055 extjs6的DateTimeField


  不知道为什么Extjs中始终没有日期和时间结合在一起的控件,这样就有了各个版本的自定义控件,但是随着版本的更新都不太兼容。在网上找了一些DateTimeField的参考过后,发现要完全的在Extjs6中实现,必须要重新生成一个DateTime的选择控件的类。网上大多数的类都是继承自 'Ext.picker.Date' ,经过一些试验过后,发现这个类的 

privates 属性不能被很好的继承,因此只能找到Ext.picker.Date的源码,重新拷贝一份来进行修改了。下面来讲解一下主要的更改地方和更改的说明。(源码的下载在最后)

					renderTpl : [
							'<div id="{id}-innerEl" data-ref="innerEl" role="presentation">',
							'<div class="{baseCls}-header">',
							'<div id="{id}-prevEl" data-ref="prevEl" class="{baseCls}-prev {baseCls}-arrow" role="presentation" title="{prevText}"></div>',
							'<div id="{id}-middleBtnEl" data-ref="middleBtnEl" class="{baseCls}-month" role="heading">{%this.renderMonthBtn(values, out)%}</div>',
							'<div id="{id}-nextEl" data-ref="nextEl" class="{baseCls}-next {baseCls}-arrow" role="presentation" title="{nextText}"></div>',
							'</div>',
							'<table role="grid" id="{id}-eventEl" data-ref="eventEl" class="{baseCls}-inner" cellspacing="0" tabindex="0" aria-readonly="true">',
							'<thead>',
							'<tr role="row">',
							'<tpl for="dayNames">',
							'<th role="columnheader" class="{parent.baseCls}-column-header" aria-label="{.}">',
							'<div role="presentation" class="{parent.baseCls}-column-header-inner">{.:this.firstInitial}</div>',
							'</th>',
							'</tpl>',
							'</tr>',
							'</thead>',
							'<tbody>',
							'<tr role="row">',
							'<tpl for="days">',
							'{#:this.isEndOfWeek}',
							'<td role="gridcell">',
							'<div hidefocus="on" class="{parent.baseCls}-date"></div>',
							'</td>',
							'</tpl>',
							'</tr>',
							'</tbody>',
							'</table>',

							// 指定时分秒渲染框架
							'<table id="{id}-timeEl" style="table-layout:auto;margin:0 auto;width:90%;text-align:center;" class="x-datepicker-inner" cellspacing="0">',
							'<tbody><tr>',
							'<td width="30%">{%this.renderHourField(values,out)%}</td>',
							'<td width="35%">{%this.renderMinuteField(values,out)%}</td>',
							'<td width="35%">{%this.renderSecondField(values,out)%}</td>',
							'</tr></tbody>',
							'</table>',
							// 上面是新增的

							'<tpl if="showToday">',
							'<div id="{id}-footerEl" data-ref="footerEl" role="presentation" class="{baseCls}-footer">',
							// 增加了确认按钮
							'{%this.renderOkBtn(values, out)%}',
							// 上面是新增的
							'{%this.renderTodayBtn(values, out)%}',
							'</div>',
							'</tpl>',
							// These elements are used with Assistive Technologies such as
							// screen readers
							'<div id="{id}-todayText" class="' + Ext.baseCSSPrefix
									+ 'hidden-clip">{todayText}.</div>',
							'<div id="{id}-ariaMinText" class="' + Ext.baseCSSPrefix
									+ 'hidden-clip">{ariaMinText}.</div>',
							'<div id="{id}-ariaMaxText" class="' + Ext.baseCSSPrefix
									+ 'hidden-clip">{ariaMaxText}.</div>',
							'<div id="{id}-ariaDisabledDaysText" class="' + Ext.baseCSSPrefix
									+ 'hidden-clip">{ariaDisabledDaysText}.</div>',
							'<div id="{id}-ariaDisabledDatesText" class="'
									+ Ext.baseCSSPrefix
									+ 'hidden-clip">{ariaDisabledDatesText}.</div>',
							'</div>',
							{
								firstInitial : function(value) {
									return Ext.picker.Date.prototype.getDayInitial(value);
								},
								isEndOfWeek : function(value) {
									// convert from 1 based index to 0 based
									// by decrementing value once.
									value--;
									var end = value % 7 === 0 && value !== 0;
									return end ? '</tr><tr role="row">' : '';
								},
								renderTodayBtn : function(values, out) {
									Ext.DomHelper.generateMarkup(values.$comp.todayBtn
											.getRenderTree(), out);
								},
								renderMonthBtn : function(values, out) {
									Ext.DomHelper.generateMarkup(values.$comp.monthBtn
											.getRenderTree(), out);
								},
								// 指定渲染方法调用
								renderHourField : function(values, out) {
									Ext.DomHelper.generateMarkup(values.$comp.hourField
											.getRenderTree(), out);
								},
								renderMinuteField : function(values, out) {
									Ext.DomHelper.generateMarkup(values.$comp.minuteField
											.getRenderTree(), out);
								},
								renderSecondField : function(values, out) {
									Ext.DomHelper.generateMarkup(values.$comp.secondField
											.getRenderTree(), out);
								},
								renderOkBtn : function(values, out) {
									Ext.DomHelper.generateMarkup(values.$comp.okBtn
											.getRenderTree(), out);
								}
							// 以上四个函数是新增的
							} ],
  首先修改了  renderTpl 这个参数,在里面加入了时分秒的录入field和一个"确定"按钮。时分秒这三个录入字段占用整个宽度的90%,这样正好能适用于各个theme。

  其次也是比较主要的一个步骤,是要将里面有些清除时间的函数修改掉。比如initComponent这个函数中。

    initComponent: function() {
        var me = this,
            clearTime = Ext.Date.clearTime;

        me.selectedCls = me.baseCls + '-selected';
        me.disabledCellCls = me.baseCls + '-disabled';
        me.prevCls = me.baseCls + '-prevday';
        me.activeCls = me.baseCls + '-active';
        me.cellCls = me.baseCls + '-cell';
        me.nextCls = me.baseCls + '-prevday';
        me.todayCls = me.baseCls + '-today';
        
        if (!me.format) {
            me.format = Ext.Date.defaultFormat;
        }
        if (!me.dayNames) {
            me.dayNames = Ext.Date.dayNames;
        }
        me.dayNames = me.dayNames.slice(me.startDay).concat(me.dayNames.slice(0, me.startDay));

        me.callParent();

        me.value = me.value ? clearTime(me.value, true) : clearTime(new Date());

        me.initDisabledDays();
    },
  上面倒数第二条语句,会清除时间,这个要去掉。因此要改成 
						me.value = me.value ? (me.value) : (new Date());

  在beforeRender的时候,需要建立这三个数值field和okbtn的实例。

					beforeRender : function() {
						/*
						 * days array for looping through 6 full weeks (6 weeks * 7 days)
						 * Note that we explicitly force the size here so the template
						 * creates all the appropriate cells.
						 */
						var me = this, encode = Ext.String.htmlEncode, days = new Array(
								me.numDays), today = Ext.Date.format(new Date(), me.format);

						if (me.padding && !me.width) {
							me.cacheWidth();
						}

						// 自己加的
						me.hourField = new Ext.form.field.Number({
							ownerCt : me,
							ownerLayout : me.getComponentLayout(),
							minValue : 0,
							maxValue : 23,
							step : 1,
							width : '100%',
							enableKeyEvents : true,
							listeners : {
								specialkey : function(field, e) {
									if (e.getKey() == e.ENTER) {
										e.stopEvent();
										me.minuteField.focus(true);
									}
								}
							}
						});
						me.minuteField = new Ext.form.field.Number({
							ownerCt : me,
							ownerLayout : me.getComponentLayout(),
							minValue : 0,
							maxValue : 59,
							step : 1,
							width : '100%',
							labelWidth : 10,
							fieldLabel : ' ',
							enableKeyEvents : true,
							listeners : {
								specialkey : function(field, e) {
									if (e.getKey() == e.ENTER) {
										e.stopEvent();
										me.secondField.focus(true);
									}
								}
							}
						});
						me.secondField = new Ext.form.field.Number({
							ownerCt : me,
							ownerLayout : me.getComponentLayout(),
							minValue : 0,
							maxValue : 59,
							step : 1,
							width : '100%',
							labelWidth : 10,
							fieldLabel : ' ',
							enableKeyEvents : true,
							listeners : {
								specialkey : function(field, e) {
									if (e.getKey() == e.ENTER) {
										e.stopEvent();
										me.okBtn.focus(true);
									}
								}
							}
						});
						// 自己加的

						me.monthBtn = new Ext.button.Split({
							ownerCt : me,
							ownerLayout : me.getComponentLayout(),
							text : '',
							tooltip : me.monthYearText,
							tabIndex : -1,
							ariaRole : 'presentation',
							listeners : {
								click : me.doShowMonthPicker,
								arrowclick : me.doShowMonthPicker,
								scope : me
							}
						});

						if (me.showToday) {

							// 自己加的
							me.okBtn = new Ext.button.Button({
								ui : me.footerButtonUI,
								ownerCt : me,
								ownerLayout : me.getComponentLayout(),
								text : me.okText,
								handler : me.okHandler, // 确认按钮的事件委托
								scope : me
							});
							// 自己加的

							me.todayBtn = new Ext.button.Button({
								ui : me.footerButtonUI,
								ownerCt : me,
								ownerLayout : me.getComponentLayout(),
								text : Ext.String.format(me.todayText, today),
								tooltip : Ext.String.format(me.todayTip, today),
								tooltipType : 'title',
								tabIndex : -1,
								ariaRole : 'presentation',
								handler : me.selectToday,
								scope : me
							});
						}

						me.callParent();

						Ext.applyIf(me, {
							renderData : {}
						});

						Ext.apply(me.renderData, {
							dayNames : me.dayNames,
							showToday : me.showToday,
							prevText : encode(me.prevText),
							nextText : encode(me.nextText),
							todayText : encode(me.todayText),
							ariaMinText : encode(me.ariaMinText),
							ariaMaxText : encode(me.ariaMaxText),
							ariaDisabledDaysText : encode(me.ariaDisabledDaysText),
							ariaDisabledDatesText : encode(me.ariaDisabledDatesText),
							days : days
						});

						me.protoEl.unselectable();
					},

  再增加一个ok按钮的执行事件。
					/**
					 * 确认 按钮触发的调用
					 */
					okHandler : function() {
						var me = this, btn = me.okBtn;
						if (btn && !btn.disabled) {
							me.setValue(this.getValue());
							me.fireEvent('select', me, me.value);
							me.onSelect();
						}
					},

  然后还需要修改一些函数:

					setValue : function(value, isfixed) {
						// If passed a null value just pass in a new date object.

						var me = this;
						// 这里一定要用 Ext.Date.clone ,不然不会触发 isDirty事件
						this.value = Ext.Date.clone(value || new Date());

						if (isfixed !== true) {
							this.value.setHours(me.hourField.getValue());
							this.value.setMinutes(me.minuteField.getValue());
							this.value.setSeconds(me.secondField.getValue());
						}

						return this.update(this.value);
					},

					update : function(date, forceRefresh) {
						var me = this, active = me.activeDate;
						me.hourField.setValue(date.getHours());
						me.minuteField.setValue(date.getMinutes());
						me.secondField.setValue(date.getSeconds());
						if (me.rendered) {
							me.activeDate = date;
							if (!forceRefresh && active && me.el
									&& active.getMonth() === date.getMonth()
									&& active.getFullYear() === date.getFullYear()) {
								me.selectedUpdate(date, active);
							} else {
								me.fullUpdate(date, active);
							}
						}
						return me;
					},
  具体还有一些修改请参见发布的源文件。

  最后再定义一个本地化的文件。

Ext.define("Ext.locale.zh_CN.picker.DateTime", {
	override : "app.ux.picker.DateTime",
	todayText : "现在",
	minText : "日期必须大于最小允许日期",
	// update
	maxText : "日期必须小于最大允许日期",
	// update
	disabledDaysText : "",
	disabledDatesText : "",
	nextText : '下个月 (Ctrl+Right)',
	prevText : '上个月 (Ctrl+Left)',
	monthYearText : '选择一个月 (Control+Up/Down 来改变年份)',
	// update
	todayTip : "{0}",
	format : "y年m月d日",
	ariaTitle : '{0}',
	ariaTitleDateFormat : 'Y\u5e74m\u6708d\u65e5',
	longDayFormat : 'Y\u5e74m\u6708d\u65e5',
	monthYearFormat : 'Y\u5e74m\u6708',
	getDayInitial : function(value) {
		// Grab the last character
		return value.substr(value.length - 1);
	}
});

  以上是DateTimePicker的控件,还需要做一个DateTimeField的控件。

Ext.define('app.module.widget.field.DateTime', {
	extend : 'Ext.form.field.Date',
	alias : 'widget.datetimefield',
	requires : [ 'app.ux.picker.DateTime' ],

	createPicker : function() {
		var me = this, format = Ext.String.format;
		return new app.ux.picker.DateTime({
			pickerField : me,
			floating : true,
			preventRefocus : true,
			hidden : true,
			minDate : me.minValue,
			maxDate : me.maxValue,
			disabledDatesRE : me.disabledDatesRE,
			disabledDatesText : me.disabledDatesText,
			ariaDisabledDatesText : me.ariaDisabledDatesText,
			disabledDays : me.disabledDays,
			disabledDaysText : me.disabledDaysText,
			ariaDisabledDaysText : me.ariaDisabledDaysText,
			format : me.format,
			showToday : me.showToday,
			startDay : me.startDay,
			minText : format(me.minText, me.formatDate(me.minValue)),
			ariaMinText : format(me.ariaMinText, me.formatDate(me.minValue,
					me.ariaFormat)),
			maxText : format(me.maxText, me.formatDate(me.maxValue)),
			ariaMaxText : format(me.ariaMaxText, me.formatDate(me.maxValue,
					me.ariaFormat)),
			listeners : {
				scope : me,
				select : me.onSelect,
				tabout : me.onTabOut
			},
			keyNavConfig : {
				esc : function() {
					me.inputEl.focus();
					me.collapse();
				}
			}
		});
	},

	onExpand : function() {
		var value = this.rawDate;
		this.picker.setValue(Ext.isDate(value) ? value : new Date(), true);
	}
})
  看一下执行的结果:

  开发过程中也遇到了不少问题,经过2天时间的排查和改进,操作都基本正常了。(此文件改用自 extjs6.0.2的源码,extjs4 和 5我没有试过,不一定能用)

源文件下载链接:https://pan.baidu.com/s/1qYJ52jU

(使用的时候注意你自己的文件的路径和类名的对应关系)。







  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值