<template> <transition name="el-zoom-in-top" @after-leave="$emit('dodestroy')"> <div v-show="visible" class="el-time-panel el-popper" :class="popperClass"> <div class="el-time-panel__content" :class="{ 'has-seconds': showSeconds }"> <time-spinner ref="spinner" @change="handleChange" :arrow-control="useArrow" :show-seconds="showSeconds" :am-pm-mode="amPmMode" @select-range="setSelectionRange" :date="date"> </time-spinner> </div> <div class="el-time-panel__footer"> <button type="button" class="el-time-panel__btn cancel" @click="handleCancel">{{ t('el.datepicker.cancel') }}</button> <button type="button" class="el-time-panel__btn" :class="{confirm: !disabled}" @click="handleConfirm()">{{ t('el.datepicker.confirm') }}</button> </div> </div> </transition> </template> <script type="text/babel"> import { limitTimeRange, isDate, clearMilliseconds, timeWithinRange } from '../util'; import Locale from 'element-ui/src/mixins/locale'; import TimeSpinner from '../basic/time-spinner'; export default { mixins: [Locale], components: { TimeSpinner }, props: { visible: Boolean, timeArrowControl: Boolean }, watch: { visible(val) { if (val) { this.oldValue = this.value; this.$nextTick(() => this.$refs.spinner.emitSelectRange('hours')); } else { this.needInitAdjust = true; } }, value(newVal) { let date; if (newVal instanceof Date) { date = limitTimeRange(newVal, this.selectableRange, this.format); } else if (!newVal) { date = this.defaultValue ? new Date(this.defaultValue) : new Date(); } this.date = date; if (this.visible && this.needInitAdjust) { this.$nextTick(_ => this.adjustSpinners()); this.needInitAdjust = false; } }, selectableRange(val) { this.$refs.spinner.selectableRange = val; }, defaultValue(val) { if (!isDate(this.value)) { this.date = val ? new Date(val) : new Date(); } } }, data() { return { popperClass: '', format: 'HH:mm:ss', value: '', defaultValue: null, date: new Date(), oldValue: new Date(), selectableRange: [], selectionRange: [0, 2], disabled: false, arrowControl: false, needInitAdjust: true }; }, computed: { showSeconds() { return (this.format || '').indexOf('ss') !== -1; }, useArrow() { return this.arrowControl || this.timeArrowControl || false; }, amPmMode() { if ((this.format || '').indexOf('A') !== -1) return 'A'; if ((this.format || '').indexOf('a') !== -1) return 'a'; return ''; } }, methods: { handleCancel() { this.$emit('pick', this.oldValue, false); }, handleChange(date) { // this.visible avoids edge cases, when use scrolls during panel closing animation if (this.visible) { this.date = clearMilliseconds(date); // if date is out of range, do not emit if (this.isValidValue(this.date)) { this.$emit('pick', this.date, true); } } }, setSelectionRange(start, end) { this.$emit('select-range', start, end); this.selectionRange = [start, end]; }, handleConfirm(visible = false, first) { if (first) return; const date = clearMilliseconds(limitTimeRange(this.date, this.selectableRange, this.format)); this.$emit('pick', date, visible, first); }, handleKeydown(event) { const keyCode = event.keyCode; const mapping = { 38: -1, 40: 1, 37: -1, 39: 1 }; // Left or Right if (keyCode === 37 || keyCode === 39) { const step = mapping[keyCode]; this.changeSelectionRange(step); event.preventDefault(); return; } // Up or Down if (keyCode === 38 || keyCode === 40) { const step = mapping[keyCode]; this.$refs.spinner.scrollDown(step); event.preventDefault(); return; } }, isValidValue(date) { return timeWithinRange(date, this.selectableRange, this.format); }, adjustSpinners() { return this.$refs.spinner.adjustSpinners(); }, 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]); } }, mounted() { this.$nextTick(() => this.handleConfirm(true, true)); this.$emit('mounted'); } }; </script>