From de284770643f4d5c70dfcc570c1829ad720829d6 Mon Sep 17 00:00:00 2001 From: Dreamacro Date: Sun, 30 Jul 2017 16:23:01 +0800 Subject: [PATCH] TimePicker: support keyboard control (#6050) * TimePicker: support keyboard control * fix time-range * fix timeformat --- .../date-picker/src/basic/time-spinner.vue | 33 +++++++++++++++- packages/date-picker/src/panel/time-range.vue | 38 ++++++++++++++++++- packages/date-picker/src/panel/time.vue | 19 +++++++++- .../date-picker/src/picker/time-picker.js | 38 +++++++++++++++++++ 4 files changed, 124 insertions(+), 4 deletions(-) diff --git a/packages/date-picker/src/basic/time-spinner.vue b/packages/date-picker/src/basic/time-spinner.vue index 012669977..3dfbdfa15 100644 --- a/packages/date-picker/src/basic/time-spinner.vue +++ b/packages/date-picker/src/basic/time-spinner.vue @@ -129,7 +129,8 @@ hoursPrivate: 0, minutesPrivate: 0, secondsPrivate: 0, - selectableRange: [] + selectableRange: [], + currentScrollbar: null }; }, @@ -162,6 +163,7 @@ } else if (type === 'seconds') { this.$emit('select-range', 6, 8); } + this.currentScrollbar = type; }, bindScrollEvent() { @@ -188,6 +190,35 @@ ajustElTop(type, value) { this[`${type}El`].scrollTop = Math.max(0, (value - 2.5) * 32 + 80); + }, + + scrollDown(step) { + if (!this.currentScrollbar) { + this.emitSelectRange('hours'); + } + + const label = this.currentScrollbar; + const hoursList = this.hoursList; + let now = this[label]; + + if (this.currentScrollbar === 'hours') { + let total = Math.abs(step); + step = step > 0 ? 1 : -1; + let length = hoursList.length; + while (length-- && total) { + now = (now + step + hoursList.length) % hoursList.length; + if (hoursList[now]) { + continue; + } + total--; + } + if (hoursList[now]) return; + } else { + now = (now + step + 60) % 60; + } + + this.$emit('change', { [label]: now }); + this.ajustElTop(label.slice(0, -1), now); } } }; diff --git a/packages/date-picker/src/panel/time-range.vue b/packages/date-picker/src/panel/time-range.vue index fca298d03..854731f1d 100644 --- a/packages/date-picker/src/panel/time-range.vue +++ b/packages/date-picker/src/panel/time-range.vue @@ -89,6 +89,14 @@ computed: { showSeconds() { return (this.format || '').indexOf('ss') !== -1; + }, + + offset() { + return this.showSeconds ? 11 : 8; + }, + + spinner() { + return this.selectionRange[0] < this.offset ? this.$refs.minSpinner : this.$refs.maxSpinner; } }, @@ -110,7 +118,8 @@ minSeconds: time.minTime.getSeconds(), format: 'HH:mm:ss', visible: false, - width: 0 + width: 0, + selectionRange: [0, 2] }; }, @@ -118,6 +127,12 @@ value(newVal) { this.panelCreated(); this.$nextTick(_ => this.ajustScrollTop()); + }, + + visible(val) { + if (val) { + this.$nextTick(() => this.$refs.minSpinner.emitSelectRange('hours')); + } } }, @@ -194,10 +209,12 @@ setMinSelectionRange(start, end) { this.$emit('select-range', start, end); + this.selectionRange = [start, end]; }, setMaxSelectionRange(start, end) { - this.$emit('select-range', start + 11, end + 11); + this.$emit('select-range', start + this.offset, end + this.offset); + this.selectionRange = [start + this.offset, end + this.offset]; }, handleConfirm(visible = false, first = false) { @@ -214,6 +231,23 @@ ajustScrollTop() { this.$refs.minSpinner.ajustScrollTop(); this.$refs.maxSpinner.ajustScrollTop(); + }, + + scrollDown(step) { + this.spinner.scrollDown(step); + }, + + changeSelectionRange(step) { + const list = this.showSeconds ? [0, 3, 6, 11, 14, 17] : [0, 3, 8, 11]; + const mapping = ['hours', 'minutes'].concat(this.showSeconds ? ['seconds'] : []); + const index = list.indexOf(this.selectionRange[0]); + const next = (index + step + list.length) % list.length; + const half = list.length / 2; + if (next < half) { + this.$refs.minSpinner.emitSelectRange(mapping[next]); + } else { + this.$refs.maxSpinner.emitSelectRange(mapping[next - half]); + } } }, diff --git a/packages/date-picker/src/panel/time.vue b/packages/date-picker/src/panel/time.vue index 0d2c11a97..32373ad38 100644 --- a/packages/date-picker/src/panel/time.vue +++ b/packages/date-picker/src/panel/time.vue @@ -54,6 +54,9 @@ watch: { visible(val) { this.currentVisible = val; + if (val) { + this.$nextTick(() => this.$refs.spinner.emitSelectRange('hours')); + } }, pickerWidth(val) { @@ -92,7 +95,8 @@ selectableRange: [], currentDate: this.$options.defaultValue || this.date || new Date(), currentVisible: this.visible || false, - width: this.pickerWidth || 0 + width: this.pickerWidth || 0, + selectionRange: [0, 2] }; }, @@ -130,6 +134,7 @@ setSelectionRange(start, end) { this.$emit('select-range', start, end); + this.selectionRange = [start, end]; }, handleConfirm(visible = false, first) { @@ -140,6 +145,18 @@ ajustScrollTop() { return this.$refs.spinner.ajustScrollTop(); + }, + + scrollDown(step) { + this.$refs.spinner.scrollDown(step); + }, + + changeSelectionRange(step) { + const list = [0, 3].concat(this.showSeconds ? [6] : []); + const mapping = ['hours', 'minutes'].concat(this.showSeconds ? ['seconds'] : []); + const index = list.indexOf(this.selectionRange[0]); + const next = (index + step + list.length) % list.length; + this.$refs.spinner.emitSelectRange(mapping[next]); } }, diff --git a/packages/date-picker/src/picker/time-picker.js b/packages/date-picker/src/picker/time-picker.js index 6834e515b..467621d30 100644 --- a/packages/date-picker/src/picker/time-picker.js +++ b/packages/date-picker/src/picker/time-picker.js @@ -34,5 +34,43 @@ export default { created() { this.type = this.isRange ? 'timerange' : 'time'; this.panel = this.isRange ? TimeRangePanel : TimePanel; + }, + + methods: { + handleKeydown(event) { + const keyCode = event.keyCode; + + // TAB or ESC + if (keyCode === 9 || keyCode === 27) { + this.pickerVisible = false; + event.stopPropagation(); + return; + } + + const mapping = { 38: -1, 40: 1, 37: -1, 39: 1 }; + + // Left or Right + if (keyCode === 37 || keyCode === 39) { + const step = mapping[keyCode]; + this.picker.changeSelectionRange(step); + event.preventDefault(); + return; + } + + // Up or Down + if (keyCode === 38 || keyCode === 40) { + const step = mapping[keyCode]; + this.picker.scrollDown(step); + event.preventDefault(); + return; + } + + if (keyCode === 13) { + this.picker.handleConfirm(); + this.$refs.reference.$refs.input.blur(); + event.preventDefault(); + return; + } + } } };