<template> <transition name="el-zoom-in-top" @before-enter="handleMenuEnter" @after-leave="$emit('dodestroy')"> <div ref="popper" v-show="visible" :style="{ width: width + 'px' }" :class="popperClass" class="el-picker-panel time-select el-popper"> <el-scrollbar noresize wrap-class="el-picker-panel__content"> <div class="time-select-item" v-for="item in items" :class="{ selected: value === item.value, disabled: item.disabled, default: item.value === defaultValue }" :disabled="item.disabled" @click="handleClick(item)">{{ item.value }}</div> </el-scrollbar> </div> </transition> </template> <script type="text/babel"> import ElScrollbar from 'element-ui/packages/scrollbar'; import scrollIntoView from 'element-ui/src/utils/scroll-into-view'; const parseTime = function(time) { const values = (time || '').split(':'); if (values.length >= 2) { const hours = parseInt(values[0], 10); const minutes = parseInt(values[1], 10); return { hours, minutes }; } /* istanbul ignore next */ return null; }; const compareTime = function(time1, time2) { const value1 = parseTime(time1); const value2 = parseTime(time2); const minutes1 = value1.minutes + value1.hours * 60; const minutes2 = value2.minutes + value2.hours * 60; if (minutes1 === minutes2) { return 0; } return minutes1 > minutes2 ? 1 : -1; }; const formatTime = function(time) { return (time.hours < 10 ? '0' + time.hours : time.hours) + ':' + (time.minutes < 10 ? '0' + time.minutes : time.minutes); }; const nextTime = function(time, step) { const timeValue = parseTime(time); const stepValue = parseTime(step); const next = { hours: timeValue.hours, minutes: timeValue.minutes }; next.minutes += stepValue.minutes; next.hours += stepValue.hours; next.hours += Math.floor(next.minutes / 60); next.minutes = next.minutes % 60; return formatTime(next); }; export default { components: { ElScrollbar }, watch: { value(val) { if (!val) return; this.$nextTick(() => this.scrollToOption()); } }, methods: { handleClick(item) { if (!item.disabled) { this.$emit('pick', item.value); } }, handleClear() { this.$emit('pick', null); }, scrollToOption(selector = '.selected') { const menu = this.$refs.popper.querySelector('.el-picker-panel__content'); scrollIntoView(menu, menu.querySelector(selector)); }, handleMenuEnter() { const selected = this.items.map(item => item.value).indexOf(this.value) !== -1; const hasDefault = this.items.map(item => item.value).indexOf(this.defaultValue) !== -1; const option = (selected && '.selected') || (hasDefault && '.default') || '.time-select-item:not(.disabled)'; this.$nextTick(() => this.scrollToOption(option)); }, scrollDown(step) { const items = this.items; const length = items.length; let total = items.length; let index = items.map(item => item.value).indexOf(this.value); while (total--) { index = (index + step + length) % length; if (!items[index].disabled) { this.$emit('pick', items[index].value, true); return; } } }, isValidValue(date) { return this.items.filter(item => !item.disabled).map(item => item.value).indexOf(date) !== -1; }, handleKeydown(event) { const keyCode = event.keyCode; if (keyCode === 38 || keyCode === 40) { const mapping = { 40: 1, 38: -1 }; const offset = mapping[keyCode.toString()]; this.scrollDown(offset); event.stopPropagation(); return; } } }, data() { return { popperClass: '', start: '09:00', end: '18:00', step: '00:30', value: '', defaultValue: '', visible: false, minTime: '', maxTime: '', width: 0 }; }, computed: { items() { const start = this.start; const end = this.end; const step = this.step; const result = []; if (start && end && step) { let current = start; while (compareTime(current, end) <= 0) { result.push({ value: current, disabled: compareTime(current, this.minTime || '-1:-1') <= 0 || compareTime(current, this.maxTime || '100:100') >= 0 }); current = nextTime(current, step); } } return result; } } }; </script>