<template>
|
<div class="el-time-spinner" :class="{ 'has-seconds': showSeconds }">
|
<template v-if="!arrowControl">
|
<el-scrollbar
|
@mouseenter.native="emitSelectRange('hours')"
|
@mousemove.native="adjustCurrentSpinner('hours')"
|
class="el-time-spinner__wrapper"
|
wrap-style="max-height: inherit;"
|
view-class="el-time-spinner__list"
|
noresize
|
tag="ul"
|
ref="hours">
|
<li
|
@click="handleClick('hours', { value: hour, disabled: disabled })"
|
v-for="(disabled, hour) in hoursList"
|
class="el-time-spinner__item"
|
:key="hour"
|
:class="{ 'active': hour === hours, 'disabled': disabled }">{{ ('0' + (amPmMode ? (hour % 12 || 12) : hour )).slice(-2) }}{{ amPm(hour) }}</li>
|
</el-scrollbar>
|
<el-scrollbar
|
@mouseenter.native="emitSelectRange('minutes')"
|
@mousemove.native="adjustCurrentSpinner('minutes')"
|
class="el-time-spinner__wrapper"
|
wrap-style="max-height: inherit;"
|
view-class="el-time-spinner__list"
|
noresize
|
tag="ul"
|
ref="minutes">
|
<li
|
@click="handleClick('minutes', { value: key, disabled: false })"
|
v-for="(enabled, key) in minutesList"
|
:key="key"
|
class="el-time-spinner__item"
|
:class="{ 'active': key === minutes, disabled: !enabled }">{{ ('0' + key).slice(-2) }}</li>
|
</el-scrollbar>
|
<el-scrollbar
|
v-show="showSeconds"
|
@mouseenter.native="emitSelectRange('seconds')"
|
@mousemove.native="adjustCurrentSpinner('seconds')"
|
class="el-time-spinner__wrapper"
|
wrap-style="max-height: inherit;"
|
view-class="el-time-spinner__list"
|
noresize
|
tag="ul"
|
ref="seconds">
|
<li
|
@click="handleClick('seconds', { value: key, disabled: false })"
|
v-for="(second, key) in 60"
|
class="el-time-spinner__item"
|
:class="{ 'active': key === seconds }"
|
:key="key">{{ ('0' + key).slice(-2) }}</li>
|
</el-scrollbar>
|
</template>
|
<template v-if="arrowControl">
|
<div
|
@mouseenter="emitSelectRange('hours')"
|
class="el-time-spinner__wrapper is-arrow">
|
<i v-repeat-click="decrease" class="el-time-spinner__arrow el-icon-arrow-up"></i>
|
<i v-repeat-click="increase" class="el-time-spinner__arrow el-icon-arrow-down"></i>
|
<ul class="el-time-spinner__list" ref="hours">
|
<li
|
class="el-time-spinner__item"
|
:class="{ 'active': hour === hours, 'disabled': hoursList[hour] }"
|
v-for="(hour, key) in arrowHourList"
|
:key="key">{{ hour === undefined ? '' : ('0' + (amPmMode ? (hour % 12 || 12) : hour )).slice(-2) + amPm(hour) }}</li>
|
</ul>
|
</div>
|
<div
|
@mouseenter="emitSelectRange('minutes')"
|
class="el-time-spinner__wrapper is-arrow">
|
<i v-repeat-click="decrease" class="el-time-spinner__arrow el-icon-arrow-up"></i>
|
<i v-repeat-click="increase" class="el-time-spinner__arrow el-icon-arrow-down"></i>
|
<ul class="el-time-spinner__list" ref="minutes">
|
<li
|
class="el-time-spinner__item"
|
:class="{ 'active': minute === minutes }"
|
v-for="(minute, key) in arrowMinuteList"
|
:key="key">
|
{{ minute === undefined ? '' : ('0' + minute).slice(-2) }}
|
</li>
|
</ul>
|
</div>
|
<div
|
@mouseenter="emitSelectRange('seconds')"
|
class="el-time-spinner__wrapper is-arrow"
|
v-if="showSeconds">
|
<i v-repeat-click="decrease" class="el-time-spinner__arrow el-icon-arrow-up"></i>
|
<i v-repeat-click="increase" class="el-time-spinner__arrow el-icon-arrow-down"></i>
|
<ul class="el-time-spinner__list" ref="seconds">
|
<li
|
v-for="(second, key) in arrowSecondList"
|
class="el-time-spinner__item"
|
:class="{ 'active': second === seconds }"
|
:key="key">
|
{{ second === undefined ? '' : ('0' + second).slice(-2) }}
|
</li>
|
</ul>
|
</div>
|
</template>
|
</div>
|
</template>
|
|
<script type="text/babel">
|
import { getRangeHours, getRangeMinutes, modifyTime } from 'element-ui/src/utils/date-util';
|
import ElScrollbar from 'element-ui/packages/scrollbar';
|
import RepeatClick from 'element-ui/src/directives/repeat-click';
|
|
export default {
|
components: { ElScrollbar },
|
|
directives: {
|
repeatClick: RepeatClick
|
},
|
|
props: {
|
date: {},
|
defaultValue: {}, // reserved for future use
|
showSeconds: {
|
type: Boolean,
|
default: true
|
},
|
arrowControl: Boolean,
|
amPmMode: {
|
type: String,
|
default: '' // 'a': am/pm; 'A': AM/PM
|
}
|
},
|
|
computed: {
|
hours() {
|
return this.date.getHours();
|
},
|
minutes() {
|
return this.date.getMinutes();
|
},
|
seconds() {
|
return this.date.getSeconds();
|
},
|
hoursList() {
|
return getRangeHours(this.selectableRange);
|
},
|
minutesList() {
|
return getRangeMinutes(this.selectableRange, this.hours);
|
},
|
arrowHourList() {
|
const hours = this.hours;
|
return [
|
hours > 0 ? hours - 1 : undefined,
|
hours,
|
hours < 23 ? hours + 1 : undefined
|
];
|
},
|
arrowMinuteList() {
|
const minutes = this.minutes;
|
return [
|
minutes > 0 ? minutes - 1 : undefined,
|
minutes,
|
minutes < 59 ? minutes + 1 : undefined
|
];
|
},
|
arrowSecondList() {
|
const seconds = this.seconds;
|
return [
|
seconds > 0 ? seconds - 1 : undefined,
|
seconds,
|
seconds < 59 ? seconds + 1 : undefined
|
];
|
}
|
},
|
|
data() {
|
return {
|
selectableRange: [],
|
currentScrollbar: null
|
};
|
},
|
|
mounted() {
|
this.$nextTick(() => {
|
!this.arrowControl && this.bindScrollEvent();
|
});
|
},
|
|
methods: {
|
increase() {
|
this.scrollDown(1);
|
},
|
|
decrease() {
|
this.scrollDown(-1);
|
},
|
|
modifyDateField(type, value) {
|
switch (type) {
|
case 'hours': this.$emit('change', modifyTime(this.date, value, this.minutes, this.seconds)); break;
|
case 'minutes': this.$emit('change', modifyTime(this.date, this.hours, value, this.seconds)); break;
|
case 'seconds': this.$emit('change', modifyTime(this.date, this.hours, this.minutes, value)); break;
|
}
|
},
|
|
handleClick(type, {value, disabled}) {
|
if (!disabled) {
|
this.modifyDateField(type, value);
|
this.emitSelectRange(type);
|
this.adjustSpinner(type, value);
|
}
|
},
|
|
emitSelectRange(type) {
|
if (type === 'hours') {
|
this.$emit('select-range', 0, 2);
|
} else if (type === 'minutes') {
|
this.$emit('select-range', 3, 5);
|
} else if (type === 'seconds') {
|
this.$emit('select-range', 6, 8);
|
}
|
this.currentScrollbar = type;
|
},
|
|
bindScrollEvent() {
|
const bindFunction = (type) => {
|
this.$refs[type].wrap.onscroll = (e) => {
|
// TODO: scroll is emitted when set scrollTop programatically
|
// should find better solutions in the future!
|
this.handleScroll(type, e);
|
};
|
};
|
bindFunction('hours');
|
bindFunction('minutes');
|
bindFunction('seconds');
|
},
|
|
handleScroll(type) {
|
const value = Math.min(Math.round((this.$refs[type].wrap.scrollTop - (this.scrollBarHeight(type) * 0.5 - 10) / this.typeItemHeight(type) + 3) / this.typeItemHeight(type)), (type === 'hours' ? 23 : 59));
|
this.modifyDateField(type, value);
|
},
|
|
// NOTE: used by datetime / date-range panel
|
// renamed from adjustScrollTop
|
// should try to refactory it
|
adjustSpinners() {
|
this.adjustSpinner('hours', this.hours);
|
this.adjustSpinner('minutes', this.minutes);
|
this.adjustSpinner('seconds', this.seconds);
|
},
|
|
adjustCurrentSpinner(type) {
|
this.adjustSpinner(type, this[type]);
|
},
|
|
adjustSpinner(type, value) {
|
if (this.arrowControl) return;
|
const el = this.$refs[type].wrap;
|
if (el) {
|
el.scrollTop = Math.max(0, value * this.typeItemHeight(type));
|
}
|
},
|
|
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.modifyDateField(label, now);
|
this.adjustSpinner(label, now);
|
this.$nextTick(() => this.emitSelectRange(this.currentScrollbar));
|
},
|
amPm(hour) {
|
let shouldShowAmPm = this.amPmMode.toLowerCase() === 'a';
|
if (!shouldShowAmPm) return '';
|
let isCapital = this.amPmMode === 'A';
|
let content = (hour < 12) ? ' am' : ' pm';
|
if (isCapital) content = content.toUpperCase();
|
return content;
|
},
|
typeItemHeight(type) {
|
return this.$refs[type].$el.querySelector('li').offsetHeight;
|
},
|
scrollBarHeight(type) {
|
return this.$refs[type].$el.offsetHeight;
|
}
|
}
|
};
|
</script>
|