Commit 9b37683241ee087399127f9c3edf64188277db3f
1 parent
f3c6cd68
Add feature: allow spinner to have steps
This ads the possibility to choose `steps` in the formatting of the lists. So we can have ”5 in five minutes” or ”every 15 minutes” instead of having always lists of 60 items/minutes.
Showing
5 changed files
with
54 additions
and
38 deletions
Show diff stats
src/components/date-picker/base/time-spinner.vue
| 1 | <template> | 1 | <template> |
| 2 | <div :class="classes"> | 2 | <div :class="classes"> |
| 3 | <div :class="[prefixCls+ '-list']" ref="hours"> | 3 | <div :class="[prefixCls+ '-list']" ref="hours"> |
| 4 | - <ul :class="[prefixCls + '-ul']" @click="handleClickHours"> | ||
| 5 | - <li :class="getCellCls(item)" v-for="(item, index) in hoursList" v-show="!item.hide" :index="index">{{ formatTime(item.text) }}</li> | 4 | + <ul :class="[prefixCls + '-ul']"> |
| 5 | + <li :class="getCellCls(item)" v-for="item in hoursList" v-show="!item.hide" @click="handleClick('hours', item)">{{ formatTime(item.text) }}</li> | ||
| 6 | </ul> | 6 | </ul> |
| 7 | </div> | 7 | </div> |
| 8 | <div :class="[prefixCls+ '-list']" ref="minutes"> | 8 | <div :class="[prefixCls+ '-list']" ref="minutes"> |
| 9 | - <ul :class="[prefixCls + '-ul']" @click="handleClickMinutes"> | ||
| 10 | - <li :class="getCellCls(item)" v-for="(item, index) in minutesList" v-show="!item.hide" :index="index">{{ formatTime(item.text) }}</li> | 9 | + <ul :class="[prefixCls + '-ul']"> |
| 10 | + <li :class="getCellCls(item)" v-for="item in minutesList" v-show="!item.hide" @click="handleClick('minutes', item)">{{ formatTime(item.text) }}</li> | ||
| 11 | </ul> | 11 | </ul> |
| 12 | </div> | 12 | </div> |
| 13 | <div :class="[prefixCls+ '-list']" v-show="showSeconds" ref="seconds"> | 13 | <div :class="[prefixCls+ '-list']" v-show="showSeconds" ref="seconds"> |
| 14 | - <ul :class="[prefixCls + '-ul']" @click="handleClickSeconds"> | ||
| 15 | - <li :class="getCellCls(item)" v-for="(item, index) in secondsList" v-show="!item.hide" :index="index">{{ formatTime(item.text) }}</li> | 14 | + <ul :class="[prefixCls + '-ul']"> |
| 15 | + <li :class="getCellCls(item)" v-for="item in secondsList" v-show="!item.hide" @click="handleClick('seconds', item)">{{ formatTime(item.text) }}</li> | ||
| 16 | </ul> | 16 | </ul> |
| 17 | </div> | 17 | </div> |
| 18 | </div> | 18 | </div> |
| @@ -41,10 +41,15 @@ | @@ -41,10 +41,15 @@ | ||
| 41 | showSeconds: { | 41 | showSeconds: { |
| 42 | type: Boolean, | 42 | type: Boolean, |
| 43 | default: true | 43 | default: true |
| 44 | + }, | ||
| 45 | + steps: { | ||
| 46 | + type: Array, | ||
| 47 | + default: () => [] | ||
| 44 | } | 48 | } |
| 45 | }, | 49 | }, |
| 46 | data () { | 50 | data () { |
| 47 | return { | 51 | return { |
| 52 | + spinerSteps: [1, 1, 1].map((one, i) => Math.abs(this.steps[i]) || one), | ||
| 48 | prefixCls: prefixCls, | 53 | prefixCls: prefixCls, |
| 49 | compiled: false | 54 | compiled: false |
| 50 | }; | 55 | }; |
| @@ -60,6 +65,7 @@ | @@ -60,6 +65,7 @@ | ||
| 60 | }, | 65 | }, |
| 61 | hoursList () { | 66 | hoursList () { |
| 62 | let hours = []; | 67 | let hours = []; |
| 68 | + const step = this.spinerSteps[0]; | ||
| 63 | const hour_tmpl = { | 69 | const hour_tmpl = { |
| 64 | text: 0, | 70 | text: 0, |
| 65 | selected: false, | 71 | selected: false, |
| @@ -67,7 +73,7 @@ | @@ -67,7 +73,7 @@ | ||
| 67 | hide: false | 73 | hide: false |
| 68 | }; | 74 | }; |
| 69 | 75 | ||
| 70 | - for (let i = 0; i < 24; i++) { | 76 | + for (let i = 0; i < 24; i += step) { |
| 71 | const hour = deepCopy(hour_tmpl); | 77 | const hour = deepCopy(hour_tmpl); |
| 72 | hour.text = i; | 78 | hour.text = i; |
| 73 | 79 | ||
| @@ -83,6 +89,7 @@ | @@ -83,6 +89,7 @@ | ||
| 83 | }, | 89 | }, |
| 84 | minutesList () { | 90 | minutesList () { |
| 85 | let minutes = []; | 91 | let minutes = []; |
| 92 | + const step = this.spinerSteps[1]; | ||
| 86 | const minute_tmpl = { | 93 | const minute_tmpl = { |
| 87 | text: 0, | 94 | text: 0, |
| 88 | selected: false, | 95 | selected: false, |
| @@ -90,7 +97,7 @@ | @@ -90,7 +97,7 @@ | ||
| 90 | hide: false | 97 | hide: false |
| 91 | }; | 98 | }; |
| 92 | 99 | ||
| 93 | - for (let i = 0; i < 60; i++) { | 100 | + for (let i = 0; i < 60; i += step) { |
| 94 | const minute = deepCopy(minute_tmpl); | 101 | const minute = deepCopy(minute_tmpl); |
| 95 | minute.text = i; | 102 | minute.text = i; |
| 96 | 103 | ||
| @@ -101,11 +108,11 @@ | @@ -101,11 +108,11 @@ | ||
| 101 | if (this.minutes === i) minute.selected = true; | 108 | if (this.minutes === i) minute.selected = true; |
| 102 | minutes.push(minute); | 109 | minutes.push(minute); |
| 103 | } | 110 | } |
| 104 | - | ||
| 105 | return minutes; | 111 | return minutes; |
| 106 | }, | 112 | }, |
| 107 | secondsList () { | 113 | secondsList () { |
| 108 | let seconds = []; | 114 | let seconds = []; |
| 115 | + const step = this.spinerSteps[2]; | ||
| 109 | const second_tmpl = { | 116 | const second_tmpl = { |
| 110 | text: 0, | 117 | text: 0, |
| 111 | selected: false, | 118 | selected: false, |
| @@ -113,7 +120,7 @@ | @@ -113,7 +120,7 @@ | ||
| 113 | hide: false | 120 | hide: false |
| 114 | }; | 121 | }; |
| 115 | 122 | ||
| 116 | - for (let i = 0; i < 60; i++) { | 123 | + for (let i = 0; i < 60; i += step) { |
| 117 | const second = deepCopy(second_tmpl); | 124 | const second = deepCopy(second_tmpl); |
| 118 | second.text = i; | 125 | second.text = i; |
| 119 | 126 | ||
| @@ -138,24 +145,11 @@ | @@ -138,24 +145,11 @@ | ||
| 138 | } | 145 | } |
| 139 | ]; | 146 | ]; |
| 140 | }, | 147 | }, |
| 141 | - handleClickHours (event) { | ||
| 142 | - this.handleClick('hours', event); | ||
| 143 | - }, | ||
| 144 | - handleClickMinutes (event) { | ||
| 145 | - this.handleClick('minutes', event); | ||
| 146 | - }, | ||
| 147 | - handleClickSeconds (event) { | ||
| 148 | - this.handleClick('seconds', event); | ||
| 149 | - }, | ||
| 150 | - handleClick (type, event) { | ||
| 151 | - const target = event.target; | ||
| 152 | - if (target.tagName === 'LI') { | ||
| 153 | - const cell = this[`${type}List`][parseInt(event.target.getAttribute('index'))]; | ||
| 154 | - if (cell.disabled) return; | ||
| 155 | - const data = {}; | ||
| 156 | - data[type] = cell.text; | ||
| 157 | - this.$emit('on-change', data); | ||
| 158 | - } | 148 | + handleClick (type, cell) { |
| 149 | + if (cell.disabled) return; | ||
| 150 | + const data = {}; | ||
| 151 | + data[type] = cell.text; | ||
| 152 | + this.$emit('on-change', data); | ||
| 159 | this.$emit('on-pick-click'); | 153 | this.$emit('on-pick-click'); |
| 160 | }, | 154 | }, |
| 161 | scroll (type, index) { | 155 | scroll (type, index) { |
| @@ -183,20 +177,24 @@ | @@ -183,20 +177,24 @@ | ||
| 183 | }, | 177 | }, |
| 184 | formatTime (text) { | 178 | formatTime (text) { |
| 185 | return text < 10 ? '0' + text : text; | 179 | return text < 10 ? '0' + text : text; |
| 180 | + }, | ||
| 181 | + getItemIndex(type, val){ | ||
| 182 | + const item = this[`${type}List`].find(obj => obj.text == val); | ||
| 183 | + return this[`${type}List`].indexOf(item); | ||
| 186 | } | 184 | } |
| 187 | }, | 185 | }, |
| 188 | watch: { | 186 | watch: { |
| 189 | hours (val) { | 187 | hours (val) { |
| 190 | if (!this.compiled) return; | 188 | if (!this.compiled) return; |
| 191 | - this.scroll('hours', val); | 189 | + this.scroll('hours', this.getItemIndex('hours', val)); |
| 192 | }, | 190 | }, |
| 193 | minutes (val) { | 191 | minutes (val) { |
| 194 | if (!this.compiled) return; | 192 | if (!this.compiled) return; |
| 195 | - this.scroll('minutes', val); | 193 | + this.scroll('minutes', this.getItemIndex('minutes', val)); |
| 196 | }, | 194 | }, |
| 197 | seconds (val) { | 195 | seconds (val) { |
| 198 | if (!this.compiled) return; | 196 | if (!this.compiled) return; |
| 199 | - this.scroll('seconds', val); | 197 | + this.scroll('seconds', this.getItemIndex('seconds', val)); |
| 200 | } | 198 | } |
| 201 | }, | 199 | }, |
| 202 | mounted () { | 200 | mounted () { |
| @@ -204,4 +202,4 @@ | @@ -204,4 +202,4 @@ | ||
| 204 | this.$nextTick(() => this.compiled = true); | 202 | this.$nextTick(() => this.compiled = true); |
| 205 | } | 203 | } |
| 206 | }; | 204 | }; |
| 207 | -</script> | ||
| 208 | \ No newline at end of file | 205 | \ No newline at end of file |
| 206 | +</script> |
src/components/date-picker/panel/time.vue
| @@ -6,6 +6,7 @@ | @@ -6,6 +6,7 @@ | ||
| 6 | <time-spinner | 6 | <time-spinner |
| 7 | ref="timeSpinner" | 7 | ref="timeSpinner" |
| 8 | :show-seconds="showSeconds" | 8 | :show-seconds="showSeconds" |
| 9 | + :steps="steps" | ||
| 9 | :hours="hours" | 10 | :hours="hours" |
| 10 | :minutes="minutes" | 11 | :minutes="minutes" |
| 11 | :seconds="seconds" | 12 | :seconds="seconds" |
| @@ -39,6 +40,12 @@ | @@ -39,6 +40,12 @@ | ||
| 39 | name: 'TimePicker', | 40 | name: 'TimePicker', |
| 40 | mixins: [ Mixin, Locale ], | 41 | mixins: [ Mixin, Locale ], |
| 41 | components: { TimeSpinner, Confirm }, | 42 | components: { TimeSpinner, Confirm }, |
| 43 | + props: { | ||
| 44 | + steps: { | ||
| 45 | + type: Array, | ||
| 46 | + default: () => [] | ||
| 47 | + } | ||
| 48 | + }, | ||
| 42 | data () { | 49 | data () { |
| 43 | return { | 50 | return { |
| 44 | prefixCls: prefixCls, | 51 | prefixCls: prefixCls, |
| @@ -113,4 +120,4 @@ | @@ -113,4 +120,4 @@ | ||
| 113 | if (this.$parent && this.$parent.$options.name === 'DatePicker') this.showDate = true; | 120 | if (this.$parent && this.$parent.$options.name === 'DatePicker') this.showDate = true; |
| 114 | } | 121 | } |
| 115 | }; | 122 | }; |
| 116 | -</script> | ||
| 117 | \ No newline at end of file | 123 | \ No newline at end of file |
| 124 | +</script> |
src/components/date-picker/picker.vue
| @@ -32,7 +32,6 @@ | @@ -32,7 +32,6 @@ | ||
| 32 | </div> | 32 | </div> |
| 33 | </template> | 33 | </template> |
| 34 | <script> | 34 | <script> |
| 35 | - import Vue from 'vue'; | ||
| 36 | import iInput from '../../components/input/input.vue'; | 35 | import iInput from '../../components/input/input.vue'; |
| 37 | import Drop from '../../components/select/dropdown.vue'; | 36 | import Drop from '../../components/select/dropdown.vue'; |
| 38 | import clickoutside from '../../directives/clickoutside'; | 37 | import clickoutside from '../../directives/clickoutside'; |
| @@ -397,7 +396,7 @@ | @@ -397,7 +396,7 @@ | ||
| 397 | let isConfirm = this.confirm; | 396 | let isConfirm = this.confirm; |
| 398 | const type = this.type; | 397 | const type = this.type; |
| 399 | 398 | ||
| 400 | - this.picker = new Vue(this.panel).$mount(this.$refs.picker); | 399 | + this.picker = this.Panel.$mount(this.$refs.picker); |
| 401 | if (type === 'datetime' || type === 'datetimerange') { | 400 | if (type === 'datetime' || type === 'datetimerange') { |
| 402 | isConfirm = true; | 401 | isConfirm = true; |
| 403 | this.picker.showTime = true; | 402 | this.picker.showTime = true; |
src/components/date-picker/picker/date-picker.js
| 1 | +import Vue from 'vue'; | ||
| 1 | import Picker from '../picker.vue'; | 2 | import Picker from '../picker.vue'; |
| 2 | import DatePanel from '../panel/date.vue'; | 3 | import DatePanel from '../panel/date.vue'; |
| 3 | import DateRangePanel from '../panel/date-range.vue'; | 4 | import DateRangePanel from '../panel/date-range.vue'; |
| @@ -31,6 +32,7 @@ export default { | @@ -31,6 +32,7 @@ export default { | ||
| 31 | } | 32 | } |
| 32 | } | 33 | } |
| 33 | 34 | ||
| 34 | - this.panel = getPanel(this.type); | 35 | + const panel = getPanel(this.type); |
| 36 | + this.Panel = new Vue(panel); | ||
| 35 | } | 37 | } |
| 36 | }; | 38 | }; |
src/components/date-picker/picker/time-picker.js
| 1 | +import Vue from 'vue'; | ||
| 1 | import Picker from '../picker.vue'; | 2 | import Picker from '../picker.vue'; |
| 2 | import TimePanel from '../panel/time.vue'; | 3 | import TimePanel from '../panel/time.vue'; |
| 3 | import TimeRangePanel from '../panel/time-range.vue'; | 4 | import TimeRangePanel from '../panel/time-range.vue'; |
| @@ -21,6 +22,10 @@ export default { | @@ -21,6 +22,10 @@ export default { | ||
| 21 | }, | 22 | }, |
| 22 | default: 'time' | 23 | default: 'time' |
| 23 | }, | 24 | }, |
| 25 | + steps: { | ||
| 26 | + type: Array, | ||
| 27 | + default: () => [] | ||
| 28 | + }, | ||
| 24 | value: {} | 29 | value: {} |
| 25 | }, | 30 | }, |
| 26 | created () { | 31 | created () { |
| @@ -31,6 +36,11 @@ export default { | @@ -31,6 +36,11 @@ export default { | ||
| 31 | this.currentValue = ''; | 36 | this.currentValue = ''; |
| 32 | } | 37 | } |
| 33 | } | 38 | } |
| 34 | - this.panel = getPanel(this.type); | 39 | + const Panel = Vue.extend(getPanel(this.type)); |
| 40 | + this.Panel = new Panel({ | ||
| 41 | + propsData: { | ||
| 42 | + steps: this.steps | ||
| 43 | + } | ||
| 44 | + }); | ||
| 35 | } | 45 | } |
| 36 | -}; | ||
| 37 | \ No newline at end of file | 46 | \ No newline at end of file |
| 47 | +}; |