<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"
|
:key="item.value"
|
@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>
|