ux.form.field.Year 只能选年的时间扩展

效果如图,亲测6.2.1版本可用,用法同时间选择控件

 

  1 //只选择年的控件
  2 Ext.define('ux.picker.Year', {
  3     extend: 'Ext.Component',
  4     alias: 'widget.uxYearpicker',
  5     alternateClassName: 'ux.uxYearpicker',
  6     cls: 'uxYearpicker',
  7     isYearPicker: true,
  8 
  9     focusable: true,
 10 
 11     childEls: [
 12         'bodyEl', 'prevEl', 'nextEl', 'yearEl'
 13     ],
 14 
 15     renderTpl: [
 16         '<div id="{id}-bodyEl" data-ref="bodyEl" class="{baseCls}-body">',
 17         '<div id="{id}-yearEl" data-ref="yearEl" class="{baseCls}-years">',
 18         '<div class="{baseCls}-yearnav">',
 19         '<div class="{baseCls}-yearnav-button-ct">',
 20         '<a id="{id}-prevEl" data-ref="prevEl" class="{baseCls}-yearnav-button {baseCls}-yearnav-prev" hidefocus="on" role="button"></a>',
 21         '</div>',
 22         '<div class="{baseCls}-yearnav-button-ct">',
 23         '<a id="{id}-nextEl" data-ref="nextEl" class="{baseCls}-yearnav-button {baseCls}-yearnav-next" hidefocus="on" role="button"></a>',
 24         '</div>',
 25         '</div>',
 26         '<tpl for="years">',
 27         '<div class="{parent.baseCls}-item {parent.baseCls}-year">',
 28         '<a hidefocus="on" class="{parent.baseCls}-item-inner" role="button">{.}</a>',
 29         '</div>',
 30         '</tpl>',
 31         '</div>',
 32         '<div class="' + Ext.baseCSSPrefix + 'clear"></div>',
 33         '<tpl if="showButtons">',
 34         '<div class="{baseCls}-buttons">{%',
 35         'var me=values.$comp, okBtn=me.okBtn, cancelBtn=me.cancelBtn;',
 36         'okBtn.ownerLayout = cancelBtn.ownerLayout = me.componentLayout;',
 37         'okBtn.ownerCt = cancelBtn.ownerCt = me;',
 38         'Ext.DomHelper.generateMarkup(okBtn.getRenderTree(), out);',
 39         'Ext.DomHelper.generateMarkup(cancelBtn.getRenderTree(), out);',
 40         '%}</div>',
 41         '</tpl>',
 42         '</div>'
 43     ],
 44 
 45     //<locale>
 46     /**
 47      * @cfg {String} okText The text to display on the ok button.
 48      */
 49     okText: '确定',
 50     //</locale>
 51 
 52     //<locale>
 53     /**
 54      * @cfg {String} cancelText The text to display on the cancel button.
 55      */
 56     cancelText: '取消',
 57     //</locale>
 58 
 59     /**
 60      * @cfg {String} [baseCls='x-monthpicker']
 61      *  The base CSS class to apply to the picker element.
 62      */
 63     baseCls: Ext.baseCSSPrefix + 'monthpicker',
 64 
 65     /**
 66      * @cfg {Boolean} showButtons True to show ok and cancel buttons below the picker.
 67      */
 68     showButtons: true,
 69 
 70     /**
 71      * @cfg {String} [selectedCls='x-monthpicker-selected'] The class to be added to selected items in the picker.
 72      */
 73 
 74     /**
 75      * @cfg {Date/Number[]} value The default value to set. See {@link #setValue}
 76      */
 77 
 78     /**
 79      * @cfg {String}
 80      * The {@link Ext.button.Button#ui} to use for the month picker's footer buttons.
 81      */
 82     footerButtonUI: 'default',
 83 
 84     measureWidth: 35,
 85     measureMaxHeight: 20,
 86 
 87     // used when attached to date picker which isnt showing buttons
 88     smallCls: Ext.baseCSSPrefix + 'monthpicker-small',
 89 
 90     /**
 91      * @private
 92      */
 93     totalYears: 10,
 94     yearOffset: 5, // 10 years in total, 2 per row
 95     monthOffset: 6, // 12 months, 2 per row
 96     alignOnScroll: false,
 97 
 98     /**
 99      * @event cancelclick
100      * Fires when the cancel button is pressed.
101      * @param {Ext.picker.Month} this
102      */
103 
104     /**
105      * @event monthclick
106      * Fires when a month is clicked.
107      * @param {Ext.picker.Month} this
108      * @param {Array} value The current value
109      */
110 
111     /**
112      * @event monthdblclick
113      * Fires when a month is clicked.
114      * @param {Ext.picker.Month} this
115      * @param {Array} value The current value
116      */
117 
118     /**
119      * @event okclick
120      * Fires when the ok button is pressed.
121      * @param {Ext.picker.Month} this
122      * @param {Array} value The current value
123      */
124 
125     /**
126      * @event select
127      * Fires when a month/year is selected.
128      * @param {Ext.picker.Month} this
129      * @param {Array} value The current value
130      */
131 
132     /**
133      * @event yearclick
134      * Fires when a year is clicked.
135      * @param {Ext.picker.Month} this
136      * @param {Array} value The current value
137      */
138 
139     /**
140      * @event yeardblclick
141      * Fires when a year is clicked.
142      * @param {Ext.picker.Month} this
143      * @param {Array} value The current value
144      */
145 
146     /**
147      * @inheritdoc
148      * @private
149      */
150     initComponent: function () {
151         var me = this;
152 
153         me.selectedCls = me.baseCls + '-selected';
154 
155         if (me.small) {
156             me.addCls(me.smallCls);
157         }
158         me.setValue(me.value);
159         me.activeYear = me.getYear(new Date().getFullYear() - 4, -4);
160 
161         if (me.showButtons) {
162             me.okBtn = new Ext.button.Button({
163                 ui: me.footerButtonUI,
164                 text: me.okText,
165                 handler: me.onOkClick,
166                 scope: me
167             });
168             me.cancelBtn = new Ext.button.Button({
169                 ui: me.footerButtonUI,
170                 text: me.cancelText,
171                 handler: me.onCancelClick,
172                 scope: me
173             });
174         }
175 
176         this.callParent();
177     },
178 
179     /**
180      * @inheritdoc
181      * @private
182      */
183     beforeRender: function () {
184         var me = this;
185 
186         if (me.padding && !me.width) {
187             me.cacheWidth();
188         }
189 
190         me.callParent();
191 
192         Ext.apply(me.renderData, {
193             years: me.getYears(),
194             showButtons: me.showButtons
195         });
196     },
197 
198     cacheWidth: function () {
199         var me = this,
200             padding = me.parseBox(me.padding),
201             widthEl = Ext.getBody().createChild({
202                 cls: me.baseCls + ' ' + me.borderBoxCls,
203                 style: 'position:absolute;top:-1000px;left:-1000px;',
204                 html: '&nbsp;' // required for opera 11.64 to measure a width
205             });
206 
207         me.self.prototype.width = widthEl.getWidth() + padding.left + padding.right;
208         widthEl.destroy();
209     },
210 
211     /**
212      * @inheritdoc
213      * @private
214      */
215     afterRender: function () {
216         var me = this,
217             body = me.bodyEl;
218 
219         me.callParent();
220 
221         me.el.on('mousedown', me.onElClick, me, {
222             translate: false
223         });
224 
225         body.on({
226             scope: me,
227             click: 'onBodyClick',
228             dblclick: 'onBodyClick'
229         });
230 
231         // keep a reference to the year/month elements since we'll be re-using them
232         me.years = body.select('.' + me.baseCls + '-year a');
233 
234         me.backRepeater = new Ext.util.ClickRepeater(me.prevEl, {
235             handler: Ext.Function.bind(me.adjustYear, me, [-me.totalYears])
236         });
237 
238         me.prevEl.addClsOnOver(me.baseCls + '-yearnav-prev-over');
239         me.nextRepeater = new Ext.util.ClickRepeater(me.nextEl, {
240             handler: Ext.Function.bind(me.adjustYear, me, [me.totalYears])
241         });
242         me.nextEl.addClsOnOver(me.baseCls + '-yearnav-next-over');
243         me.updateBody();
244 
245     },
246 
247     /**
248      * Set the value for the picker.
249      * @param {Date/Number[]} value The value to set. It can be a Date object, where the month/year will be extracted, or
250      * it can be an array, with the month as the first index and the year as the second.
251      * @return {Ext.picker.Month} this
252      */
253     setValue: function (value) {
254         var me = this,
255             active = me.activeYear,
256             year;
257 
258         if (!value) {
259             me.value = [null, null];
260         } else if (Ext.isDate(value)) {
261             me.value = [value.getMonth(), value.getFullYear()];
262         } else {
263             me.value = [value[0], value[1]];
264         }
265 
266         if (me.rendered) {
267             year = me.value[1];
268             if (year !== null) {
269                 if ((year < active || year > active + me.yearOffset)) {
270                     me.activeYear = year - me.yearOffset + 1;
271                 }
272             }
273             me.updateBody();
274         }
275 
276         return me;
277     },
278 
279     /**
280      * Gets the selected value. It is returned as an array [month, year]. It may
281      * be a partial value, for example [null, 2010]. The month is returned as
282      * 0 based.
283      * @return {Number[]} The selected value
284      */
285     getValue: function () {
286         return this.value;
287     },
288 
289     /**
290      * Checks whether the picker has a selection
291      * @return {Boolean} Returns true if both a month and year have been selected
292      */
293     hasSelection: function () {
294         var value = this.value;
295         return value[0] !== null && value[1] !== null;
296     },
297 
298     /**
299      * Get an array of years to be pushed in the template. It is not in strict
300      * numerical order because we want to show them in columns.
301      * @private
302      * @return {Number[]} An array of years
303      */
304     getYears: function () {
305         var me = this,
306             offset = me.yearOffset,
307             start = me.activeYear, // put the "active" year on the left
308             end = start + offset,
309             i = start,
310             years = [];
311 
312         for (; i < end; ++i) {
313             years.push(i, i + offset);
314         }
315 
316         return years;
317     },
318 
319     /**
320      * Update the years in the body based on any change
321      * @private
322      */
323     updateBody: function () {
324         var me = this,
325             years = me.years,
326             yearNumbers = me.getYears(),
327             cls = me.selectedCls,
328             value = me.getYear(null),
329             year,
330             yearItems, y, yLen, el;
331 
332         if (me.rendered) {
333             years.removeCls(cls);
334 
335             yearItems = years.elements;
336             yLen = yearItems.length;
337 
338             for (y = 0; y < yLen; y++) {
339                 el = Ext.fly(yearItems[y]);
340 
341                 year = yearNumbers[y];
342                 el.dom.innerHTML = year;
343                 if (year === value) {
344                     el.addCls(cls);
345                 }
346             }
347         }
348     },
349 
350     /**
351      * Gets the current year value, or the default.
352      * @private
353      * @param {Number} defaultValue The default value to use if the year is not defined.
354      * @param {Number} offset A number to offset the value by
355      * @return {Number} The year value
356      */
357     getYear: function (defaultValue, offset) {
358         var year = this.value[1];
359         offset = offset || 0;
360         return year === null ? defaultValue : year + offset;
361     },
362 
363     onElClick: function (e) {
364         e.stopEvent();
365     },
366 
367     /**
368      * React to clicks on the body
369      * @private
370      */
371     onBodyClick: function (e, t) {
372         var me = this,
373             isDouble = e.type === 'dblclick';
374 
375         if (e.getTarget('.' + me.baseCls + '-year')) {
376             e.stopEvent();
377             me.onYearClick(t, isDouble);
378         }
379     },
380 
381     /**
382      * Modify the year display by passing an offset.
383      * @param {Number} [offset=10] The offset to move by.
384      */
385     adjustYear: function (offset) {
386         if (typeof offset !== 'number') {
387             offset = this.totalYears;
388         }
389         this.activeYear += offset;
390         this.updateBody();
391     },
392 
393     /**
394      * React to the ok button being pressed
395      * @private
396      */
397     onOkClick: function () {
398         this.fireEvent('okclick', this, this.value);
399     },
400 
401     /**
402      * React to the cancel button being pressed
403      * @private
404      */
405     onCancelClick: function () {
406         this.fireEvent('cancelclick', this);
407     },
408 
409     /**
410      * React to a year being clicked
411      * @private
412      * @param {HTMLElement} target The element that was clicked
413      * @param {Boolean} isDouble True if the event was a doubleclick
414      */
415     onYearClick: function (target, isDouble) {
416         var me = this;
417         me.value[1] = me.activeYear + me.resolveOffset(me.years.indexOf(target), me.yearOffset);
418         me.updateBody();
419         me.fireEvent('year' + (isDouble ? 'dbl' : '') + 'click', me, me.value);
420         me.fireEvent('select', me, me.value);
421 
422     },
423 
424     /**
425      * Returns an offsetted number based on the position in the collection. Since our collections aren't
426      * numerically ordered, this function helps to normalize those differences.
427      * @private
428      * @param {Object} index
429      * @param {Object} offset
430      * @return {Number} The correctly offsetted number
431      */
432     resolveOffset: function (index, offset) {
433         if (index % 2 === 0) {
434             return (index / 2);
435         }
436         return offset + Math.floor(index / 2);
437     },
438 
439     /**
440      * @inheritdoc
441      * @private
442      */
443     beforeDestroy: function () {
444         var me = this;
445         me.years = me.months = null;
446         Ext.destroyMembers(me, 'backRepeater', 'nextRepeater', 'okBtn', 'cancelBtn');
447         me.callParent();
448     },
449 
450     onDestroy: function () {
451         Ext.destroyMembers(this, 'okBtn', 'cancelBtn');
452         this.callParent();
453     },
454 
455     privates: {
456         // Do the job of a container layout at this point even though we are not a Container.
457         // TODO: Refactor as a Container.
458         finishRenderChildren: function () {
459             var me = this;
460 
461             this.callParent(arguments);
462 
463             if (this.showButtons) {
464                 me.okBtn.finishRender();
465                 me.cancelBtn.finishRender();
466             }
467         }
468     }
469 });
 1 //只选择年的控件
 2 Ext.define('ux.form.field.Year', {
 3     extend: 'Ext.form.field.Date',
 4     alias: 'widget.uxYearfield',
 5     xtype: 'uxYearfield',
 6     requires: ['ux.picker.Year'],
 7     format: 'Y',
 8     selectYear: new Date(),
 9     createPicker: function () {
10         var me = this;
11         return new ux.picker.Year({
12             value: new Date(),
13             renderTo: document.body,
14             floating: true,
15             hidden: true,
16             focusOnShow: true,
17             listeners: {
18                 scope: me,
19                 select: me.onSelect,
20                 cancelclick: me.onCancelClick,
21                 okclick: me.onOKClick,
22                 yeardblclick: me.onOKClick,
23                 monthdblclick: me.onOKClick
24             }
25         });
26     },
27     onCancelClick: function () {
28         var me = this;
29         me.selectYear = null;
30         me.collapse();
31     },
32     onOKClick: function () {
33         var me = this;
34         if (me.selectYear) {
35             me.setValue(me.selectYear);
36             me.fireEvent('select', me, me.selectYear);
37         }
38         me.collapse();
39     },
40     onSelect: function (m, d) {
41         var me = this;
42         me.selectYear = new Date((d[0] + 1) + '/1/' + d[1]);
43     }
44 });

 

posted @ 2018-08-08 18:19  魔狼再世  阅读(541)  评论(1编辑  收藏  举报