Ext4 中 日期和时间的控件

一。一些废话

近日来,有几个项目用到了EXTJS作为Web前端。也看到了一些童鞋苦苦在网上寻觅可以选择时间的控件,由于EXTJS版本差异较大,利用官方3.2的Demo制作了一个可以选择到秒的时间控件,该控件只能够用于ExtJs2.2以上的版本。经过测试ExtJs2.02版本不适用该控件,如果你还在使用2.02这个版本或者更老,请绕道。废话不说了,看代码:

二。文件明细:

Spinner.js

SpinnerField.js

DateTimeField.js

三。各文件详解

1.Spinner.js

EXTJS个版本略有不同,最后的文件解压后请覆盖源文件。这里不做详细介绍。

2.SpinnerField.js

EXTJS个版本略有不同,最后的文件解压后请覆盖源文件。这里不做详细介绍。

3.DateTimeField.js

Js代码  收藏代码
  1. // 命名空间归属  
  2. Ext.ns('Ext.ux.form');  
  3. // 在该命名空间内,开辟一个名为TimePickerField的区域,我们可以当他是一个时间选择器  
  4. Ext.ux.form.TimePickerField = function(config){  
  5.     // 调用构造方法,也就是说定义了他的所属--this  
  6.     // this指的是什么呢?这里需要注意,首先这个东东属于这个类(对象),其次这个类(对象)在没有被调用之前或者实例之前是不会被构造的  
  7.     // 那么这个this实际上是指我们实例化后的datetimefield  
  8.     Ext.ux.form.TimePickerField.superclass.constructor.call(this, config);  
  9. }  
  10. // 给刚刚定义的TimePickerField加点菜吧。  
  11. // 首先它继承与Ext.form.Field,是一个扩展  
  12. Ext.extend(Ext.ux.form.TimePickerField, Ext.form.Field, {  
  13.     defaultAutoCreate: {  
  14.         tag: 'div'// 定义了一个DIV标签  
  15.     },  
  16.     cls: 'x-form-timepickerfield',// 它的样式  
  17.     hoursSpinner: null,// 属性:小时选择器  
  18.     minutesSpinner: null,// 属性:分钟选择器  
  19.     secondsSpinner: null,// 属性:秒选择器  
  20.     spinnerCfg: {  
  21.         width: 40// 选择器的宽度定位40px  
  22.     },  
  23.       
  24.     // 约束:选择数值约束,如果小于最小值该如何,如果大于最大值该如何,这里的处理方式我详细说明一下(这个约束是触发的,我们输入的值或者我们点击上下箭头选择的值后都会进入该约束检查。)  
  25.     spinnerFixBoundries: function(value){  
  26.         // 这里有可能会造成不解,我解释一下。  
  27.         // 如果我们选择秒的时候,有一个向上的箭头和向下的箭头,如果我点击向上的箭头则秒数加1,点击向下的箭头则秒数减1。  
  28.         // 如果我选择了59秒后,点击向上的箭头,由于时间秒数约束,不可能出现60,那我们要怎么办?会如何?当然是,58,59,0,1这样的序列  
  29.         // 所以最大值定义为59,如果超过59那么秒数归零,就是这个逻辑。  
  30.         if (value < this.field.minValue) {  
  31.             value = this.field.maxValue;  
  32.         }  
  33.         if (value > this.field.maxValue) {  
  34.             value = this.field.minValue;  
  35.         }  
  36.         // 这里返回了一个带有精度的值  
  37.         return this.fixPrecision(value);  
  38.     },  
  39.     // 渲染,这个没什么可说的了所有的渲染都差不多是位置和范围之类的  
  40.     onRender: function(ct, position){  
  41.         Ext.ux.form.TimePickerField.superclass.onRender.call(this, ct, position);  
  42.         this.rendered = false;  
  43.         this.date = new Date();  
  44.         // 定义一个对象,他即将有三个属性,时分秒数值,往下看。  
  45.         var values = {};  
  46.         // 如果实例时已经被设定了初始值,那么将这些值赋予values这个对象中。  
  47.         // 再将这些值表示在时分秒选择器中  
  48.         if (this.value) {  
  49.             values = this._valueSplit(this.value);  
  50.             this.date.setHours(values.h);  
  51.             this.date.setMinutes(values.m);  
  52.             this.date.setSeconds(values.s);  
  53.             delete this.value;  
  54.         }  
  55.         // 如果实例时没被设定了初始值,简单了,时分秒选择器的初始值就不用改变了,只要values得到这些值备用即可  
  56.         else {  
  57.             values = {  
  58.                 h: this.date.getHours(),  
  59.                 m: this.date.getMinutes(),  
  60.                 s: this.date.getSeconds()  
  61.             };  
  62.         }  
  63.         // 定义一个外围包裹,就是想把时分秒这三个选择器给包起来成为一组,下面会实例这三个选择器的,往下看。  
  64.         var spinnerWrap = Ext.DomHelper.append(this.el, {  
  65.             tag: 'div'  
  66.         });  
  67.         var cfg = Ext.apply({}, this.spinnerCfg, {  
  68.             renderTo: spinnerWrap,  
  69.             readOnly: this.readOnly,  
  70.             disabled: this.disabled,  
  71.             listeners: {  
  72.                 spin: {  
  73.                     fn: this.onSpinnerChange,  
  74.                     scope: this  
  75.                 },  
  76.                 valid: {  
  77.                     fn: this.onSpinnerChange,  
  78.                     scope: this  
  79.                 },  
  80.                 afterrender: {  
  81.                     fn: function(spinner){  
  82.                         spinner.wrap.applyStyles('float: left');  
  83.                     },  
  84.                     single: true  
  85.                 }  
  86.             }  
  87.         });  
  88.         // 接下来实例(Ext.ux.form.SpinnerField)了几个选择器,时分秒。  
  89.         this.hoursSpinner = new Ext.ux.form.SpinnerField(Ext.apply({}, cfg, {  
  90.             minValue: 0,  
  91.             maxValue: 23,  
  92.             cls: 'first',  
  93.             value: values.h  
  94.         }));  
  95.         this.minutesSpinner = new Ext.ux.form.SpinnerField(Ext.apply({}, cfg, {  
  96.             minValue: 0,  
  97.             maxValue: 59,  
  98.             value: values.m  
  99.         }));  
  100.         this.secondsSpinner = new Ext.ux.form.SpinnerField(Ext.apply({}, cfg, {  
  101.             minValue: 0,  
  102.             maxValue: 59,  
  103.             value: values.s  
  104.         }));  
  105.         Ext.DomHelper.append(spinnerWrap, {  
  106.             tag: 'div',  
  107.             cls: 'x-form-clear-left'  
  108.         });  
  109.         // 渲染完毕释放出去  
  110.         this.rendered = true;  
  111.     },  
  112.     // 如果实例时已经被设定了初始值,那么调用这个方法,将这些值赋予values这个对象中。  
  113.     _valueSplit: function(v){  
  114.         var split = v.split(':');  
  115.         return {  
  116.             h: split.length > 0 ? split[0] : 0,  
  117.             m: split.length > 1 ? split[1] : 0,  
  118.             s: split.length > 2 ? split[2] : 0  
  119.         };  
  120.     },  
  121.     // 注意了,这里加了一个动作的监听,也可以说是自己弄了一个自定义监听  
  122.     onSpinnerChange: function(){  
  123.         if (!this.rendered) {  
  124.             return;  
  125.         }  
  126.         // 这里注册了这个监听类别,指明了监听的对象  
  127.         this.fireEvent('change', this, this.getRawValue());  
  128.     },  
  129.     // 禁用  
  130.     disable: function(){  
  131.         Ext.ux.form.TimePickerField.superclass.disable.call(this);  
  132.         this.hoursSpinner.disable();  
  133.         this.minutesSpinner.disable();  
  134.         this.secondsSpinner.disable();  
  135.     },  
  136.     // 解用  
  137.     enable: function(){  
  138.         Ext.ux.form.TimePickerField.superclass.enable.call(this);  
  139.         this.hoursSpinner.enable();  
  140.         this.minutesSpinner.enable();  
  141.         this.secondsSpinner.enable();  
  142.     },  
  143.     // 只读  
  144.     setReadOnly: function(r){  
  145.         Ext.ux.form.TimePickerField.superclass.setReadOnly.call(this, r);  
  146.         this.hoursSpinner.setReadOnly(r);  
  147.         this.minutesSpinner.setReadOnly(r);  
  148.         this.secondsSpinner.setReadOnly(r);  
  149.     },  
  150.     // 清除所有的无效验证  
  151.     clearInvalid: function(){  
  152.         Ext.ux.form.TimePickerField.superclass.clearInvalid.call(this);  
  153.         this.hoursSpinner.clearInvalid();  
  154.         this.minutesSpinner.clearInvalid();  
  155.         this.secondsSpinner.clearInvalid();  
  156.     },  
  157.     // 拿到那个值,可以认为是vlaues对象  
  158.     getRawValue: function(){  
  159.         if (!this.hoursSpinner) {  
  160.             this.date = new Date();  
  161.             return {  
  162.                 h: this.date.getHours(),  
  163.                 m: this.date.getMinutes(),  
  164.                 s: this.date.getSeconds()  
  165.             };  
  166.         }  
  167.         else {  
  168.             return {  
  169.                 h: this.hoursSpinner.getValue(),  
  170.                 m: this.minutesSpinner.getValue(),  
  171.                 s: this.secondsSpinner.getValue()  
  172.             };  
  173.         }  
  174.     },  
  175.     // 赋值  
  176.     setRawValue: function(v){  
  177.         this.hoursSpinner.setValue(v.h);  
  178.         this.minutesSpinner.setValue(v.m);  
  179.         this.secondsSpinner.setValue(v.s);  
  180.     },  
  181.     // 有效验证  
  182.     isValid: function(preventMark){  
  183.         return this.hoursSpinner.isValid(preventMark) &&  
  184.         this.minutesSpinner.isValid(preventMark) &&  
  185.         this.secondsSpinner.isValid(preventMark);  
  186.     },  
  187.     // 验证  
  188.     validate: function(){  
  189.         return this.hoursSpinner.validate() &&  
  190.         this.minutesSpinner.validate() &&  
  191.         this.secondsSpinner.validate();  
  192.     },  
  193.     // 这里可以自己修改想要的格式,这个值将作为返回值到调用该类的元控件中也就是DateTimeField的实例  
  194.     getValue: function(){  
  195.         var v = this.getRawValue();  
  196.         return String.leftPad(v.h, 2, '0') + ':' +  
  197.         String.leftPad(v.m, 2, '0') +  
  198.         ':' +  
  199.         String.leftPad(v.s, 2, '0');  
  200.     },  
  201.     setValue: function(value){  
  202.         if (!this.rendered) {  
  203.             this.value = value;  
  204.             return;  
  205.         }  
  206.         value = this._valueSplit(value);  
  207.         this.setRawValue(value);  
  208.         this.validate();  
  209.     }  
  210. });  
  211.   
  212. // 下面就没什么好说的了,就是将上面自定义的类(对象),成为一个总选择器一部分。  
  213. Ext.form.TimePickerField = Ext.ux.form.TimePickerField;  
  214. Ext.reg('timepickerfield', Ext.form.TimePickerField);  
  215. Ext.ns('Ext.ux.form');  
  216. Ext.DateTimePicker = Ext.extend(Ext.DatePicker, {  
  217.     timeFormat: 'g:i:s A',  
  218.     timeLabel: '时间',  
  219.     timeWidth: 100,  
  220.     initComponent: function(){  
  221.         Ext.DateTimePicker.superclass.initComponent.call(this);  
  222.         this.id = Ext.id();  
  223.     },  
  224.     onRender: function(container, position){  
  225.         Ext.DateTimePicker.superclass.onRender.apply(this, arguments);  
  226.         var table = Ext.get(Ext.DomQuery.selectNode('table tbody', container.dom));  
  227.         var tfEl = Ext.DomHelper.insertBefore(table.last(), {  
  228.             tag: 'tr',  
  229.             children: [{  
  230.                 tag: 'td',  
  231.                 cls: 'x-date-bottom',  
  232.                 html: this.timeLabel,  
  233.                 style: 'width:30;'  
  234.             }, {  
  235.                 tag: 'td',  
  236.                 cls: 'x-date-bottom ux-timefield',  
  237.                 colspan: '2'  
  238.             }]  
  239.         }, true);  
  240.         this.tf.render(table.child('td.ux-timefield'));  
  241.         var p = this.getEl().parent('div.x-layer');  
  242.         if (p) {  
  243.             p.setStyle("height", p.getHeight() + 31);  
  244.         }  
  245.     },  
  246.     setValue: function(value){  
  247.         var old = this.value;  
  248.         if (!this.tf) {  
  249.             this.tf = new Ext.ux.form.TimePickerField();  
  250.             this.tf.ownerCt = this;  
  251.         }  
  252.         this.value = this.getDateTime(value);  
  253.     },  
  254.     getDateTime: function(value){  
  255.         if (this.tf) {  
  256.             var dt = new Date();  
  257.             var timeval = this.tf.getValue();  
  258.             value = Date.parseDate(value.format(this.dateFormat) + ' ' + this.tf.getValue(), this.format);  
  259.         }  
  260.         return value;  
  261.     },  
  262.     selectToday: function(){  
  263.         if (this.todayBtn && !this.todayBtn.disabled) {  
  264.             this.value = this.getDateTime(new Date());  
  265.             this.fireEvent("select", this, this.value);  
  266.         }  
  267.     }  
  268. });  
  269. Ext.reg('datetimepickerfield', Ext.DateTimePicker);  
  270. if (parseInt(Ext.version.substr(0, 1), 10) > 2) {  
  271.     Ext.menu.DateTimeItem = Ext.DateTimePicker;  
  272.     Ext.override(Ext.menu.DateMenu, {  
  273.         initComponent: function(){  
  274.             this.on('beforeshow', this.onBeforeShow, this);  
  275.             if (this.strict = (Ext.isIE7 && Ext.isStrict)) {  
  276.                 this.on('show', this.onShow, this, {  
  277.                     single: true,  
  278.                     delay: 20  
  279.                 });  
  280.             }  
  281.             Ext.apply(this, {  
  282.                 plain: true,  
  283.                 showSeparator: false,  
  284.                 items: this.picker = new Ext.DatePicker(Ext.apply({  
  285.                     internalRender: this.strict || !Ext.isIE,  
  286.                     ctCls: 'x-menu-date-item'  
  287.                 }, this.initialConfig))  
  288.             });  
  289.             Ext.menu.DateMenu.superclass.initComponent.call(this);  
  290.             this.relayEvents(this.picker, ["select"]);  
  291.             this.on('select', this.menuHide, this);  
  292.             if (this.handler) {  
  293.                 this.on('select', this.handler, this.scope || this);  
  294.             }  
  295.         }  
  296.     });  
  297. }  
  298. else {  
  299.     Ext.menu.DateTimeItem = function(config){  
  300.         Ext.menu.DateTimeItem.superclass.constructor.call(this, new Ext.DateTimePicker(config), config);  
  301.         this.picker = this.component;  
  302.         this.addEvents('select');  
  303.           
  304.         this.picker.on("render", function(picker){  
  305.             picker.getEl().swallowEvent("click");  
  306.             picker.container.addClass("x-menu-date-item");  
  307.         });  
  308.           
  309.         this.picker.on("select", this.onSelect, this);  
  310.     };  
  311.       
  312.     Ext.extend(Ext.menu.DateTimeItem, Ext.menu.DateMenu, {  
  313.         onSelect: function(picker, date){  
  314.             this.fireEvent("select", this, date, picker);  
  315.             Ext.menu.DateTimeItem.superclass.handleClick.call(this);  
  316.         }  
  317.     });  
  318. }  
  319.   
  320. Ext.menu.DateTimeMenu = function(config){  
  321.     Ext.menu.DateTimeMenu.superclass.constructor.call(this, config);  
  322.     this.plain = true;  
  323.     var di = new Ext.menu.DateTimeItem(config);  
  324.     this.add(di);  
  325.     this.picker = di;  
  326.     this.relayEvents(di, ["select"]);  
  327.       
  328.     this.on('beforeshow', function(){  
  329.         if (this.picker) {  
  330.             this.picker.hideMonthPicker(true);  
  331.         }  
  332.     }, this);  
  333. };  
  334. Ext.extend(Ext.menu.DateTimeMenu, Ext.menu.Menu, {  
  335.     cls: 'x-date-menu',  
  336.     beforeDestroy: function(){  
  337.         this.picker.destroy();  
  338.     },  
  339.     hide: function(deep){  
  340.         if (this.picker.tf.innerList) {  
  341.             if ((Ext.EventObject.within(this.picker.tf.innerList)) || (Ext.get(Ext.EventObject.getTarget()) == this.picker.tf.innerList))   
  342.                 return false;  
  343.         }  
  344.         if (this.el && this.isVisible()) {  
  345.             this.fireEvent("beforehide", this);  
  346.             if (this.activeItem) {  
  347.                 this.activeItem.deactivate();  
  348.                 this.activeItem = null;  
  349.             }  
  350.             this.el.hide();  
  351.             this.hidden = true;  
  352.             this.fireEvent("hide", this);  
  353.         }  
  354.         if (deep === true && this.parentMenu) {  
  355.             this.parentMenu.hide(true);  
  356.         }  
  357.     }  
  358. });  
  359.   
  360. Ext.ux.form.DateTimeField = Ext.extend(Ext.form.DateField, {  
  361.     dateFormat: 'Y-m-d',  
  362.     timeFormat: 'H:i:s',  
  363.     defaultAutoCreate: {  
  364.         tag: "input",  
  365.         type: "text",  
  366.         size: "20",  
  367.         autocomplete: "off"  
  368.     },  
  369.     initComponent: function(){  
  370.         Ext.ux.form.DateTimeField.superclass.initComponent.call(this);  
  371.         this.format = this.dateFormat + ' ' + this.timeFormat;  
  372.         this.afterMethod('afterRender', function(){  
  373.             this.getEl().applyStyles('top:0');  
  374.         });  
  375.     },  
  376.     getValue: function(){  
  377.         return this.parseDate(Ext.form.DateField.superclass.getValue.call(this)) || '';  
  378.     },  
  379.     onTriggerClick: function(){  
  380.         if (this.disabled) {  
  381.             return;  
  382.         }  
  383.         if (this.menu == null) {  
  384.             this.menu = new Ext.menu.DateTimeMenu();  
  385.         }  
  386.         Ext.apply(this.menu.picker, {  
  387.             minDate: this.minValue,  
  388.             maxDate: this.maxValue,  
  389.             disabledDatesRE: this.ddMatch,  
  390.             disabledDatesText: this.disabledDatesText,  
  391.             disabledDays: this.disabledDays,  
  392.             disabledDaysText: this.disabledDaysText,  
  393.             format: this.format,  
  394.             timeFormat: this.timeFormat,  
  395.             dateFormat: this.dateFormat,  
  396.             showToday: this.showToday,  
  397.             minText: String.format(this.minText, this.formatDate(this.minValue)),  
  398.             maxText: String.format(this.maxText, this.formatDate(this.maxValue))  
  399.         });  
  400.         if (this.menuEvents) {  
  401.             this.menuEvents('on');  
  402.         }  
  403.         else {  
  404.             this.menu.on(Ext.apply({}, this.menuListeners, {  
  405.                 scope: this  
  406.             }));  
  407.         }  
  408.         this.menu.picker.setValue(this.getValue() || new Date());  
  409.         this.menu.show(this.el, "tl-bl?");  
  410.     }  
  411. });  
  412. Ext.reg('datetimefield', Ext.ux.form.DateTimeField);  

 四。示例截图:

posted @ 2015-05-21 21:47  7号路灯  阅读(507)  评论(0编辑  收藏  举报