sencha touch datepicker/datepickerfield(时间选择控件)扩展
参考资料: https://market.sencha.com/extensions/datetimepicker
适用于2.4.1版本
uxPickerTime
使用方法参考:datepicker控件
Ext.define('ux.picker.Time', {
extend: 'Ext.picker.Picker',
xtype: 'uxPickerTime',
alternateClassName: 'uxPickerTime',
requires: ['Ext.DateExtras', 'Ext.util.InputBlocker'],
/**
* @event change
* Fired when the value of this picker has changed and the done button is pressed.
* @param {Ext.picker.Date} this This Picker
* @param {Date} value The date value
*/
config: {
/**
* @cfg {Number} yearFrom
* 开始年份,如果他比yearTo大,则选择顺序颠倒
* @accessor
*/
yearFrom: 2014,
/**
* @cfg {Number} [yearTo=new Date().getFullYear()]
* 结束年份
* @accessor
*/
yearTo: 2000,
/**
* @cfg {String} monthText
* 月显示值
* @accessor
*/
monthText: '月',
/**
* @cfg {String} dayText
* 日显示值
* @accessor
*/
dayText: '日',
/**
* @cfg {String} yearText
* 年显示值
* @accessor
*/
yearText: '年',
/**
* @cfg {String} hourText
* 小时显示值
*/
hourText: '时',
/**
* @cfg {String} minuteText
* 分显示值
*/
minuteText: '分',
/**
* @cfg {String} ampmText
* 上午/下午显示值
*/
ampmText: '上午/下午',
/**
* @cfg {Array} slotOrder
* 默认的选项列表
* @accessor
*/
slotOrder: ['year', 'month', 'day', 'hour', 'minute'], //
/**
* @cfg {Int}
*分钟间隔
* @accessor
*/
minuteInterval: 1,
/**
* @cfg {Boolean} ampm
*是否使用12小时制
* @accessor
*/
ampm: false,
useTitles: true
},
platformConfig: [{
theme: ['Windows'],
doneButton: {
iconCls: 'check2',
ui: 'round',
text: ''
}
}],
initialize: function () {
this.callParent();
this.on({
scope: this,
delegate: '> slot',
slotpick: this.onSlotPick
});
this.on({
scope: this,
show: this.onSlotPick
});
},
setValue: function (value, animated) {
if (Ext.isDate(value)) {
var ampm = 'AM',
currentHours = hour = value.getHours();
if (this.getAmpm()) {
if (currentHours > 12) {
ampm = "PM";
hour -= 12;
} else if (currentHours == 12) {
ampm = "PM";
} else if (currentHours == 0) {
hour = 12;
}
}
value = {
day: value.getDate(),
month: value.getMonth() + 1,
year: value.getFullYear(),
hour: hour,
minute: value.getMinutes(),
ampm: ampm
};
}
this.callParent([value, animated]);
this.onSlotPick();
},
//获取值
getValue: function (useDom) {
var values = {},
items = this.getItems().items,
ln = items.length,
daysInMonth, day, month, year, hour, minute, item, i;
for (i = 0; i < ln; i++) {
item = items[i];
if (item instanceof Ext.picker.Slot) {
values[item.getName()] = item.getValue(useDom);
}
}
//if all the slots return null, we should not return a date
if (values.year === null && values.month === null && values.day === null && values.hour === null && values.minute === null) {
return null;
}
year = Ext.isNumber(values.year) ? values.year : 1;
month = Ext.isNumber(values.month) ? values.month : 1;
day = Ext.isNumber(values.day) ? values.day : 1;
hour = Ext.isNumber(values.hour) ? values.hour : 1;
minute = Ext.isNumber(values.minute) ? values.minute : 1;
if (month && year && month && day) {
daysInMonth = this.getDaysInMonth(month, year);
}
day = (daysInMonth) ? Math.min(day, daysInMonth) : day;
if (values.ampm && values.ampm == "PM" && hour < 12) {
hour = hour + 12;
}
if (values.ampm && values.ampm == "AM" && hour == 12) {
hour = 0;
}
return new Date(year, month - 1, day, hour, minute);
},
/**
* Updates the yearFrom configuration
*/
updateYearFrom: function () {
if (this.initialized) {
this.createSlots();
}
},
/**
* Updates the yearTo configuration
*/
updateYearTo: function () {
if (this.initialized) {
this.createSlots();
}
},
/**
* Updates the monthText configuration
*/
updateMonthText: function (newMonthText, oldMonthText) {
var innerItems = this.getInnerItems,
ln = innerItems.length,
item, i;
//loop through each of the current items and set the title on the correct slice
if (this.initialized) {
for (i = 0; i < ln; i++) {
item = innerItems[i];
if ((typeof item.title == "string" && item.title == oldMonthText) || (item.title.html == oldMonthText)) {
item.setTitle(newMonthText);
}
}
}
},
/**
* Updates the {@link #dayText} configuration.
*/
updateDayText: function (newDayText, oldDayText) {
var innerItems = this.getInnerItems,
ln = innerItems.length,
item, i;
//loop through each of the current items and set the title on the correct slice
if (this.initialized) {
for (i = 0; i < ln; i++) {
item = innerItems[i];
if ((typeof item.title == "string" && item.title == oldDayText) || (item.title.html == oldDayText)) {
item.setTitle(newDayText);
}
}
}
},
/**
* Updates the yearText configuration
*/
updateYearText: function (yearText) {
var innerItems = this.getInnerItems,
ln = innerItems.length,
item, i;
//loop through each of the current items and set the title on the correct slice
if (this.initialized) {
for (i = 0; i < ln; i++) {
item = innerItems[i];
if (item.title == this.yearText) {
item.setTitle(yearText);
}
}
}
},
// @private
constructor: function () {
this.callParent(arguments);
this.createSlots();
},
/**
* Generates all slots for all years specified by this component, and then sets them on the component
* @private
*/
createSlots: function () {
var me = this,
slotOrder = me.getSlotOrder(),
yearsFrom = me.getYearFrom(),
yearsTo = me.getYearTo(),
years = [],
days = [],
months = [],
hours = [],
minutes = [],
ampm = [],
reverse = yearsFrom > yearsTo,
ln, i, daysInMonth;
if (!this.getAmpm()) {
var index = slotOrder.indexOf('ampm')
if (index >= 0) {
slotOrder.splice(index);
}
}
//填充年列表
while (yearsFrom) {
years.push({
text: yearsFrom,
value: yearsFrom
});
if (yearsFrom === yearsTo) {
break;
}
if (reverse) {
yearsFrom--;
} else {
yearsFrom++;
}
}
//填充天列表
daysInMonth = me.getDaysInMonth(1, new Date().getFullYear());
for (i = 0; i < daysInMonth; i++) {
days.push({
text: i + 1,
value: i + 1
});
}
//填充月列表
for (i = 0, ln = Ext.Date.monthNames.length; i < ln; i++) {
months.push({
text: Ext.Date.monthNames[i],
value: i + 1
});
}
//填充小时列表
var hourLimit = (this.getAmpm()) ? 12 : 23
var hourStart = (this.getAmpm()) ? 1 : 0
for (i = hourStart; i <= hourLimit; i++) {
hours.push({
text: this.pad2(i),
value: i
});
}
//填充分钟列表
for (i = 0; i < 60; i += this.getMinuteInterval()) {
minutes.push({
text: this.pad2(i),
value: i
});
}
//填充上午/下午
ampm.push({
text: '上午',
value: 'AM'
}, {
text: '下午',
value: 'PM'
});
var slots = [];
slotOrder.forEach(function (item) {
slots.push(me.createSlot(item, days, months, years, hours, minutes, ampm));
});
me.setSlots(slots);
},
/**
* Returns a slot config for a specified date.
* @private
*/
createSlot: function (name, days, months, years, hours, minutes, ampm) {
switch (name) {
case 'year':
return {
name: 'year',
align: 'center',
data: years,
title: this.getYearText(),
flex: 3
};
case 'month':
return {
name: name,
align: 'center',
data: months,
title: this.getMonthText(),
flex: 3
};
case 'day':
return {
name: 'day',
align: 'center',
data: days,
width: '1px',
title: this.getDayText(),
flex: 2
};
case 'hour':
return {
name: 'hour',
align: 'center',
data: hours,
title: this.getHourText(),
flex: 2
};
case 'minute':
return {
name: 'minute',
align: 'center',
data: minutes,
title: this.getMinuteText(),
flex: 2
};
case 'ampm':
return {
name: 'ampm',
align: 'center',
data: ampm,
title: this.getAmpmText(),
flex: 2
};
}
},
onSlotPick: function () {
var value = this.getValue(true),
slot = this.getDaySlot(),
year = value.getFullYear(),
month = value.getMonth(),
days = [],
daysInMonth, i;
if (!value || !Ext.isDate(value) || !slot) {
return;
}
this.callParent(arguments);
//get the new days of the month for this new date
daysInMonth = this.getDaysInMonth(month + 1, year);
for (i = 0; i < daysInMonth; i++) {
days.push({
text: i + 1,
value: i + 1
});
}
// We don't need to update the slot days unless it has changed
if (slot.getStore().getCount() == days.length) {
return;
}
slot.getStore().setData(days);
// Now we have the correct amount of days for the day slot, lets update it
var store = slot.getStore(),
viewItems = slot.getViewItems(),
valueField = slot.getValueField(),
index, item;
index = store.find(valueField, value.getDate());
if (index == -1) {
return;
}
item = Ext.get(viewItems[index]);
slot.selectedIndex = index;
slot.scrollToItem(item);
slot.setValue(slot.getValue(true));
},
getDaySlot: function () {
var innerItems = this.getInnerItems(),
ln = innerItems.length,
i, slot;
if (this.daySlot) {
return this.daySlot;
}
for (i = 0; i < ln; i++) {
slot = innerItems[i];
if (slot.isSlot && slot.getName() == "day") {
this.daySlot = slot;
return slot;
}
}
return null;
},
// @private
getDaysInMonth: function (month, year) {
var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
return month == 2 && this.isLeapYear(year) ? 29 : daysInMonth[month - 1];
},
// @private
isLeapYear: function (year) {
return !!((year & 3) === 0 && (year % 100 || (year % 400 === 0 && year)));
},
onDoneButtonTap: function () {
var oldValue = this._value,
newValue = this.getValue(true),
testValue = newValue;
if (Ext.isDate(newValue)) {
testValue = newValue.toDateString();
}
if (Ext.isDate(oldValue)) {
oldValue = oldValue.toDateString();
}
if (testValue != oldValue) {
this.fireEvent('change', this, newValue);
}
this.hide();
Ext.util.InputBlocker.unblockInputs();
},
pad2: function (number) {
return (number < 10 ? '0' : '') + number;
}
});
uxFieldTime
使用方法参考:datepickerfield控件
Ext.define('ux.field.Time', {
extend: 'Ext.field.Text',
alternateClassName: 'uxFieldTime',
xtype: 'uxFieldTime',
requires: [
'ux.picker.Time',
'Ext.DateExtras'
],
/**
* @event change
* Fires when a date is selected
* @param {Ext.field.DatePicker} this
* @param {Date} newDate The new date
* @param {Date} oldDate The old date
*/
config: {
ui: 'select',
/**
* @cfg {Object/ux.picker.Time} picker
* An object that is used when creating the internal {@link ux.picker.Time} component or a direct instance of {@link ux.picker.Time}.
* @accessor
*/
picker: true,
/**
* @cfg {Boolean}
* @hide
* @accessor
*/
clearIcon: false,
/**
* @cfg {Object/Date} value
* Default value for the field and the internal {@link ux.picker.Time} component. Accepts an object of 'year',
* 'month' and 'day' values, all of which should be numbers, or a {@link Date}.
*
* Example: {year: 1989, day: 1, month: 5} = 1st May 1989 or new Date()
* @accessor
*/
/**
* @cfg {Boolean} destroyPickerOnHide
* 完成选择时隐藏或者销毁该控件,默认销毁
* @accessor
*/
destroyPickerOnHide: false,
/**
* @cfg {String} dateFormat 默认时间格式
* 接受任何有效的时间格式. 请参考 {@link Ext.Date}.
*/
dateFormat: 'Y-m-d H:i',
/**
* @cfg {Object}
* @hide
*/
component: {
useMask: true
}
},
initialize: function () {
var me = this,
component = me.getComponent();
me.callParent();
component.on({
scope: me,
masktap: 'onMaskTap'
});
component.doMaskTap = Ext.emptyFn;
if (Ext.browser.is.AndroidStock2) {
component.input.dom.disabled = true;
}
},
syncEmptyCls: Ext.emptyFn,
applyValue: function (value) {
if (!Ext.isDate(value) && !Ext.isObject(value)) {
return null;
}
if (Ext.isObject(value)) {
return new Date(value.year, value.month - 1, value.day, value.hour, value.minute);
}
return value;
},
updateValue: function (newValue, oldValue) {
var me = this,
picker = me._picker;
if (picker && picker.isPicker) {
picker.setValue(newValue);
}
// Ext.Date.format expects a Date
if (newValue !== null) {
me.getComponent().setValue(Ext.Date.format(newValue, me.getDateFormat() || Ext.util.Format.defaultDateFormat));
} else {
me.getComponent().setValue('');
}
if (newValue !== oldValue) {
me.fireEvent('change', me, newValue, oldValue);
}
},
/**
* Updates the date format in the field.
* @private
*/
updateDateFormat: function (newDateFormat, oldDateFormat) {
var value = this.getValue();
if (newDateFormat != oldDateFormat && Ext.isDate(value)) {
this.getComponent().setValue(Ext.Date.format(value, newDateFormat || Ext.util.Format.defaultDateFormat));
}
},
/**
* Returns the {@link Date} value of this field.
* If you wanted a formated date
* @return {Date} The date selected
*/
getValue: function () {
if (this._picker && this._picker instanceof ux.picker.Time) {
return this._picker.getValue();
}
return this._value;
},
/**
* Returns the value of the field formatted using the specified format. If it is not specified, it will default to
* {@link #dateFormat} and then {@link Ext.util.Format#defaultDateFormat}.
* @param {String} format The format to be returned.
* @return {String} The formatted date.
*/
getFormattedValue: function (format) {
var value = this.getValue();
return (Ext.isDate(value)) ? Ext.Date.format(value, format || this.getDateFormat() || Ext.util.Format.defaultDateFormat) : value;
},
applyPicker: function (picker, pickerInstance) {
if (pickerInstance && pickerInstance.isPicker) {
picker = pickerInstance.setConfig(picker);
}
return picker;
},
getPicker: function () {
var picker = this._picker,
value = this.getValue();
if (picker && !picker.isPicker) {
picker = Ext.factory(picker, ux.picker.Time);
if (value != null) {
picker.setValue(value);
}
}
picker.on({
scope: this,
change: 'onPickerChange',
hide: 'onPickerHide'
});
this._picker = picker;
return picker;
},
/**
* @private
* Listener to the tap event of the mask element. Shows the internal DatePicker component when the button has been tapped.
*/
onMaskTap: function () {
if (this.getDisabled()) {
return false;
}
this.onFocus();
return false;
},
/**
* Called when the picker changes its value.
* @param {ux.picker.Time} picker The date picker.
* @param {Object} value The new value from the date picker.
* @private
*/
onPickerChange: function (picker, value) {
var me = this,
oldValue = me.getValue();
me.setValue(value);
me.fireEvent('select', me, value);
me.onChange(me, value, oldValue);
},
/**
* Override this or change event will be fired twice. change event is fired in updateValue
* for this field. TOUCH-2861
*/
onChange: Ext.emptyFn,
/**
* Destroys the picker when it is hidden, if
* {@link Ext.field.DatePicker#destroyPickerOnHide destroyPickerOnHide} is set to `true`.
* @private
*/
onPickerHide: function () {
var me = this,
picker = me.getPicker();
if (me.getDestroyPickerOnHide() && picker) {
picker.destroy();
me._picker = me.getInitialConfig().picker || true;
}
},
reset: function () {
this.setValue(this.originalValue);
},
onFocus: function (e) {
var component = this.getComponent();
this.fireEvent('focus', this, e);
if (Ext.os.is.Android4) {
component.input.dom.focus();
}
component.input.dom.blur();
if (this.getReadOnly()) {
return false;
}
this.isFocused = true;
this.getPicker().show();
},
// @private
destroy: function () {
var picker = this._picker;
if (picker && picker.isPicker) {
picker.destroy();
}
this.callParent(arguments);
}
//<deprecated product=touch since=2.0>
}, function () {
this.override({
getValue: function (format) {
if (format) {
//<debug warn>
Ext.Logger.deprecate("format argument of the getValue method is deprecated, please use getFormattedValue instead", this);
//</debug>
return this.getFormattedValue(format);
}
return this.callOverridden();
}
});
/**
* @method getDatePicker
* @inheritdoc Ext.field.DatePicker#getPicker
* @deprecated 2.0.0 Please use #getPicker instead
*/
Ext.deprecateMethod(this, 'getDatePicker', 'getPicker');
//</deprecated>
});
效果图:

只需要时、分选项如下:
xtype: 'uxFieldTime',
picker: {
slotOrder: ['hour', 'minute']
},
dateFormat: 'H:i',
value: new Date(),
label: '时间:',
placeHolder: '请输入时间'

一些额外的css:
/*#region pick */
.x-picker-slot-title {
height:auto;
text-align:center;
padding:0.2em 0;
}
.x-picker-slot .x-dataview-item {
padding:0 8px !important;
}
.x-webkit .x-layout-box.x-horizontal > .x-layout-box-item.x-picker-slot {
width:auto !important;
}
/*#endregion*/
sencha touch datepicker/datepickerfield(时间选择控件)扩展的更多相关文章
- sencha touch datepicker/datepickerfield(时间选择控件)扩展(废弃 仅参考)
参考资料:https://market.sencha.com/extensions/datetimepicker 上面的扩展在2.2有些问题,参考源码重新写了一个 TimePicker: Ext.de ...
- 基于zepto的移动端日期和时间选择控件
前段时间给大家分享过一个基于jQuery Mobile的移动端日期时间拾取器,大家反应其由于加载过大的插件导致影响调用速度.那么今天我把从网络上搜集到的两个适合移动端应用的日期和时间选择插件分享给大家 ...
- wpf timePicker 时间选择控件
wpf里有日期选择控件,但没有时间选择控件.其他地方也有类似的,但效果并不太好,而且复杂.所以就自己写了个.参考codeproject上的. 分两部分. 第一部分是.cs文件.也就是control控件 ...
- 共享MFC每周时间选择控件代码
自己写的周时间选择控件,原理就是在Static上用GDI画图. 支持选择每周内每一天内的任意时间段,可以任意拖动修改时间段,任意合并时间段 效果如下图: VS2012代码下载:https://gith ...
- WinForm时间选择控件(DateTimePicker)如何选择(显示)时分秒
C# Windows窗体应用中,用到时间选择控件DateTimePicker,发现不能选择时分秒,难道要自己写一个控件?! 答案是否定的,通过属性修改是可以选择时间的,DateTimePicker完全 ...
- 给easyui datebox时间框控件扩展一个清空的实例
给easyui datebox扩展一个清空的实例 步骤一:拓展插件 /** * 给时间框控件扩展一个清除的按钮 */ $.fn.datebox.defaults.cleanText = '清空'; ( ...
- Extjs DateTime 日期时间选择控件 (非点击日期强制选择) 支持4.0以上
Extjs的日期控件,仅仅能支持到日期选择,对时间的选择并不完好.而网上下载的控件,都是基于Ext.form.dateField 开发.在选中日期后自己主动选择,并隐藏此选择窗体. 在经过一番改造后, ...
- bootstrap-datetimepicker:基于twitter bootstrap的日期/时间选择控件
bootstrap-datetimepicker是一个基于twitter bootstrap的简单日期/时间选择控件. <!DOCTYPE HTML> <html> <h ...
- 2019-8-30-win10-uwp-好看的时间选择控件
title author date CreateTime categories win10 uwp 好看的时间选择控件 lindexi 2019-08-30 08:57:20 +0800 2018-0 ...
随机推荐
- Detour3.0 win7 64bit下的安装
最近在做API hook相关的东西,用了inline hook后感觉不错,但是查找资料发现inline hook并不稳定 inline hook 的原理是在系统访问一个函数的时候先替换原函数入口处的内 ...
- 1.Linux进程--进程标识号
函数原型 pid_t fork(void); fork的奇异之处在于它被调用一次,却返回两次,它可能有三种不同的返回值: 1.在父进程中.fork返回新创建的子进程的PID 2.在子进程中,fork返 ...
- IIS服务命令
: iisreset /reboot 重启win2k计算机(但有提示系统将重启信息出现) iisreset /start或stop 启动(停止)所有Internet服务 iisreset /resta ...
- Eclipse复制项目彻底修改项目名称
一.需求 需要新做一个项目,框架还是Maven+SSM,于是就把原来的项目copy了一个,操作是直接选中原项目,CTRL+C ,然后粘贴,这个时候会让你选择工作空间和给一个新的项目名字,如下图,输入新 ...
- 一个可以参考的JVM内存分配
下面是java命令有关JVM内存分配的参数 JAVA_MEM_OPTS="" BITS=`java -version >& | -bit` if [ -n " ...
- 【PMP】项目的定义和特点
1.定义 项目是为创建独特的产品.服务和成果而进行的的临时性工作. 2.特点 2.1 独特的产品.服务或成果 实现项目目标可能产生一个或多个可交付成果.例如:即便采用相同的材料或者相同的施工单位来建设 ...
- ROS分布式控制的节点配置
首先在终端中输入下面的指令查看ROS主节点主机的IP和远程控制端的IP: ifconfig 比如机器人控制器中运行着ROS主节点,其IP地址为192.168.1.111,hostname为xubunt ...
- 【转】《iOS7 by Tutorials》系列:iOS7的设计精髓(下)
四.聚焦于内容 在iOS7里,强调的不是眼花缭乱的装饰效果,而是最重要的内容本身. 下面我们来探讨这个主题: 1.删除不必要的内容 伟大的设计更多是减法和加法的组合. 虽然很酷的想法是很重要,但还有更 ...
- elasticsearch日志删除命令
通过curl发送DELETE命令给elasticsearch服务器,进行日志删除操作.命令示例如下: curl -XDELETE *' curl -XDELETE 'http://192.168.10 ...
- 简单的redis测试
//这个方法会多一次 public function testRedisList(){ $num = 10; $user_id = uniqid(); //直接链接本地的redis $redis = ...