實現(xiàn)如下可以自定義時間選項的時間組件母赵。
<CustomTimePicker
v-model="movie.playTime"
:defaultTime="defaultTime"
:prevTime="prevTime"
:duration="duration"
@cacul="getTime(s_index, m_index, movie)"
></CustomTimePicker>
<template>
<!-- 這是個很不成熟的組件垃僚,一次性組件瞬女,用完即拋 -->
<!-- 這是個很不成熟的組件川背,一次性組件,用完即拋 -->
<!-- 這是個很不成熟的組件暮顺,一次性組件隆箩,用完即拋 -->
<div class="custom-timer-picker-container">
<div @click.stop="showTimeFun()" style="position: relative;">
<el-input
placeholder="請選擇時間"
:value="value"
@mouseenter.native="handleMouseEnter()"
@mouseleave.native="handleMouseLeave()"
>
<i slot="prefix" class="el-input__icon el-icon-time"></i>
<i slot="suffix"
class="el-input__icon"
@click.stop="handleClickIcon()"
:class="[showClose ? '' + 'el-icon-circle-close' : '']">
</i>
</el-input>
</div>
<div class="custom-timer-picker" v-clickoutside="handleClose" :style="{ visibility: pickerVisible ? 'visible' : 'hidden' }">
<transition name="el-zoom-in-top" @after-leave="$emit('dodestroy')">
<div class="el-time-panel">
<div class="el-time-panel__content">
<div class="time-box">
<!-- 時 -->
<el-scrollbar
@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.stop="handleClick('hours', { value: item.hour, index: index, disabled: item.disabled })"
v-for="(item, index) in hourList"
:key="item.hour"
class="el-time-spinner__item"
:class="{ 'active': item.hour === hours, 'disabled': item.disabled }"
>
{{ item.hour }}
</li>
</el-scrollbar>
<!-- 分 -->
<el-scrollbar
@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.stop="handleClick('minutes', { value: item.minute, index: index, disabled: item.disabled })"
v-for="(item, index) in minuteList"
:key="item.minute"
class="el-time-spinner__item"
:class="{ 'active': item.minute === minutes, 'disabled': item.disabled }"
>
{{ item.minute }}
</li>
</el-scrollbar>
<!-- 秒 -->
<el-scrollbar
@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.stop="handleClick('seconds', { value: item.second, index: index, disabled: item.disabled })"
v-for="(item, index) in secondList"
:key="item.second"
class="el-time-spinner__item"
:class="{ 'active': item.second === seconds, 'disabled': item.disabled }"
>
{{ item.second }}
</li>
</el-scrollbar>
</div>
</div>
<div class="el-time-panel__footer">
<button
type="button"
class="el-time-panel__btn cancel"
@click.stop="handleCancel">取消</button>
<button
type="button"
class="el-time-panel__btn confirm"
@click.stop="handleConfirm()">確定</button>
</div>
</div>
</transition>
</div>
</div>
</template>
<script>
import Clickoutside from 'element-ui/src/utils/clickoutside';
export default {
props: {
// defaultTime用于設置當前時間控件的默認時間,點擊取消按鈕或者選擇了 disabled 的時間的場景使用
defaultTime: {
type: String,
default () {
return ''
}
},
// prevTime表示前一個設置的最大播放時間琼梆,配合 duration 用于計算當前時間控件可選的最早時間
prevTime: {
type: String,
default () {
return ''
}
},
// duration表示前一個設置最大播放時間的影片的播放時長性誉,配合 prevTime 用于計算當前時間控件可選的最早時間
duration: {
type: Number,
default () {
return 0
}
},
// 當前時間控件的時間
value: null
},
directives: {
Clickoutside
},
data() {
return {
pickerVisible: false,
showClose: false,
hours: '',
minutes: '',
seconds: '',
limitTime: '06:00:00',
hourList: [
{
hour: '06',
disabled: false
},
{
hour: '07',
disabled: false
},
{
hour: '08',
disabled: false
},
{
hour: '09',
disabled: false
},
{
hour: '10',
disabled: false
},
{
hour: '11',
disabled: false
},
{
hour: '12',
disabled: false
},
{
hour: '13',
disabled: false
},
{
hour: '14',
disabled: false
},
{
hour: '15',
disabled: false
},
{
hour: '16',
disabled: false
},
{
hour: '17',
disabled: false
},
{
hour: '18',
disabled: false
},
{
hour: '19',
disabled: false
},
{
hour: '20',
disabled: false
},
{
hour: '21',
disabled: false
},
{
hour: '22',
disabled: false
},
{
hour: '23',
disabled: false
}
],
minuteList: [
{
minute: '00',
disabled: false
},
{
minute: '15',
disabled: false
},
{
minute: '30',
disabled: false
},
{
minute: '45',
disabled: false
},
{
minute: '59',
disabled: false
}
],
secondList: [
{
second: '00',
disabled: false
},
{
second: '59',
disabled: false
}
]
}
},
watch: {
'pickerVisible'(val) {
if(val) {
this.init_hours_minutes_seconds()
this.$nextTick(()=>{ //這是必要的,不然秒級的59選項選不上
this.adjustSpinners()
this.initHourDisableItem()
this.initMinuteDisableItem()
})
}
},
'hours'(newVal) {
if(newVal == '23') {
if(!this.minuteList.some(item => item.minute == '59')) {
this.minuteList.push({minute: '59', disabled: false})
}
} else {
if(this.minuteList.some(item => item.minute == '59')) {
this.minuteList.pop()
if(this.minutes == '59') {
this.minutes = this.minuteList[this.minuteList.length - 1].minute
this.adjustSpinners()
}
}
}
this.initMinuteDisableItem()
// 在可選范圍區(qū)域茎杂,則emit
if(this.checkStatus()) {
let time = `${this.hours}:${this.minutes}:${this.seconds}`
this.pickVal(time, true)
}
},
'minutes'(newVal) {
if(newVal == '59') {
if(!this.secondList.some(item => item.second == '59')) {
this.secondList.push({second: '59', disabled: false})
}
} else {
if(this.secondList.some(item => item.second == '59')) {
this.secondList.pop()
if(this.seconds == '59') {
this.seconds = this.secondList[this.secondList.length - 1].second
this.adjustSpinners()
}
}
}
this.initHourDisableItem()
// 在可選范圍區(qū)域错览,則emit
if(this.checkStatus()) {
let time = `${this.hours}:${this.minutes}:${this.seconds}`
this.pickVal(time, true)
}
},
'seconds'() {
// 在可選范圍區(qū)域,則emit
if(this.checkStatus()) {
let time = `${this.hours}:${this.minutes}:${this.seconds}`
this.pickVal(time, true)
}
}
},
mounted() {
this.$nextTick(() => {
this.bindScrollEvent();
});
},
methods: {
showTimeFun() {
// 調(diào)用 cacul 方法先獲取 defaultTime蛉顽、prevTime蝗砾、duration
this.$emit('cacul')
setTimeout(() => {
this.pickerVisible = true
})
},
handleClose () {
this.pickerVisible = false
},
handleMouseEnter() {
if(this.value) {
this.showClose = true
}
},
handleMouseLeave() {
this.showClose = false
},
handleClickIcon() {
this.pickVal('', true)
},
generateTimeList(delta) {
let f = n => `${n}`.padStart(2, '0')
let result = [], date = new Date()
date.setHours(6)
date.setMinutes(delta)
let day = date.getDate()
while (date.getDate() === day) {
let h = date.getHours()
let m = date.getMinutes()
result.push(`${f(h)}:${f(m)}:00`)
date.setMinutes(m + delta)
}
result = ['06:00:00', ...result, '23:59:59']
return result
},
getLimitTimeToSeconds() {
let sum = 0
sum += this.$moment.duration(this.prevTime).as('seconds'); // 上一部電影播放時間轉化成秒
sum += this.duration // 加上上一部電影的播放時長
if(this.prevTime || this.duration) {
sum += 8 * 60 // 先加上8分鐘(這是最早能選擇的時間)
}
if(this.prevTime) {
sum -= 6 * 60 * 60 // 因為從6點開始選擇時間,所以減去6個小時的秒數(shù)
}
return sum
},
getLimitTime() {
let timeToseconds = this.getLimitTimeToSeconds()
let time = ''
let timeArr = this.generateTimeList(15)
for(let i = 0; i < timeArr.length; i++) {
let totalTime = this.$moment.duration(timeArr[i]).as('seconds') - 6 * 60 * 60 // 需要減去6個小時
if(totalTime > timeToseconds) { // 找到第一個能選擇的時間
time = timeArr[i]
break
}
}
return time
},
init_hours_minutes_seconds() {
// 如果當前時間空間選擇了時間的話携冤,并且為可選時間悼粮,那么初始化為已選擇的時間
// 如果沒有選擇時間,那么使用上一個時間控件選擇的時間加上時長轉化過來的時分秒加上8分鐘
// 如果上個控件沒有時間曾棕,也沒有時長扣猫,那么使用 06:00:00
let isBeyond = false
if(this.prevTime) {
isBeyond = this.$moment.duration(this.prevTime).as('seconds') + this.duration + 8*60 > this.$moment.duration(this.defaultTime).as('seconds')
} else if(this.duration) {
isBeyond = this.duration + 8*60 + 6*60*60 > this.$moment.duration(this.defaultTime).as('seconds')
}
if (isBeyond) {
let time = this.getLimitTime()
if(time) {
this.limitTime = time // 這是最早能選擇的可選項時間
let arr = time.split(':')
this.hours = arr[0]
this.minutes = arr[1]
this.seconds = arr[2]
} else {
// 找不到時間了 證明已經(jīng)排滿時間了 則全部置灰
this.hours = '23'
this.minutes = '59'
this.seconds = '59'
}
return false
}
if (this.defaultTime) {
let arr = this.defaultTime.split(':')
this.hours = arr[0]
this.minutes = arr[1]
this.seconds = arr[2]
return false
}
if (this.value) {
let arr = this.value.split(':')
this.hours = arr[0]
this.minutes = arr[1]
this.seconds = arr[2]
return false
}
this.hours = '06'
this.minutes = '00'
this.seconds = '00'
},
bindScrollEvent() {
const bindFuntion = (type) => {
this.$refs[type].wrap.onscroll = (e) => {
this.handleScroll(type, e);
};
};
bindFuntion('hours');
bindFuntion('minutes');
bindFuntion('seconds');
},
handleScroll(type) {
let a = this.$refs[type].wrap.scrollTop
let b = this.scrollBarHeight(type) * 0.5 - 10
let c = this.typeItemHeight(type)
let d = type === 'hours' ? this.hourList.length - 1 : type === 'minutes' ? this.minuteList.length - 1 : this.secondList.length - 1
const index = Math.min(Math.round((a - b / c + 3) / c), d);
this.modifyDateField(type, index);
},
modifyDateField(type, index, value) {
switch (type) {
case 'hours':
this.hours = this.hourList[index].hour;
break
case 'minutes':
this.minutes = this.minuteList[index].minute;
break
case 'seconds':
this.seconds = this.secondList[index].second;
break
}
},
checkStatus() {
let hourArr = this.hourList.filter(item => item.hour == this.hours)
let minuteArr = this.minuteList.filter(item => item.minute == this.minutes)
let secondArr = this.secondList.filter(item => item.second == this.seconds)
return !hourArr[0].disabled && !minuteArr[0].disabled && !secondArr[0].disabled
},
scrollBarHeight(type) {
return this.$refs[type].$el.offsetHeight;
},
typeItemHeight(type) {
return this.$refs[type].$el.querySelector('li').offsetHeight;
},
getLiIndex(type, value) {
let index = 0
if(type == 'hours') index = this.hourList.findIndex(item => item.hour == value)
if(type == 'minutes') index = this.minuteList.findIndex(item => item.minute == value)
if(type == 'seconds') index = this.secondList.findIndex(item => item.second == value)
return index
},
handleClick(type, {value, index, disabled}) {
if (!disabled) {
this.modifyDateField(type, index, value);
this.adjustSpinner(type, value);
}
},
adjustCurrentSpinner(type) {
this.adjustSpinner(type, this[type]);
},
adjustSpinners() {
this.adjustSpinner('hours', this.hours);
this.adjustSpinner('minutes', this.minutes);
this.adjustSpinner('seconds', this.seconds);
},
adjustSpinner(type, value) {
const el = this.$refs[type].wrap;
if (el) {
let index = this.getLiIndex(type, value)
el.scrollTop = Math.max(0, index * this.typeItemHeight(type));
}
},
handleConfirm() {
if(this.checkStatus()) {
let time = `${this.hours}:${this.minutes}:${this.seconds}`
this.pickVal(time, false)
} else {
this.pickVal(this.defaultTime, false)
}
},
handleCancel() {
this.pickVal(this.defaultTime, false)
},
pickVal(time, visible) {
if(!visible) {
this.pickerVisible = false
}
this.$emit('input', time)
},
initHourDisableItem() {
let currentTime = ''
for(let i = 0; i < this.hourList.length; i++) {
for(let j = 0; j < this.minuteList.length; j++) {
if(this.minuteList[j].minute == this.minutes) {
for(let k = 0; k < this.secondList.length; k++) {
currentTime = `${this.hourList[i].hour}:${this.minuteList[j].minute}:${this.secondList[k].second}`
let the_currentTime_seconds = this.$moment.duration(currentTime).as('seconds') - 6 * 60 * 60 // 需要減去6個小時;
let the_earliest_limitTime_secondes = this.getLimitTimeToSeconds()
if(the_currentTime_seconds < the_earliest_limitTime_secondes) {
this.hourList[i].disabled = true
this.secondList[k].disabled = true
} else {
this.hourList[i].disabled = false
this.secondList[k].disabled = false
}
if(the_currentTime_seconds >= 24 * 60 * 60) {
this.hourList[i].disabled = true
this.secondList[k].disabled = true
}
}
break
}
}
}
},
initMinuteDisableItem() {
let currentTime = ''
for(let i = 0; i < this.hourList.length; i++) {
if(this.hourList[i].hour == this.hours) {
for(let j = 0; j < this.minuteList.length; j++) {
for(let k = 0; k < this.secondList.length; k++) {
currentTime = `${this.hourList[i].hour}:${this.minuteList[j].minute}:${this.secondList[k].second}`
let the_currentTime_seconds = this.$moment.duration(currentTime).as('seconds') - 6 * 60 * 60 // 需要減去6個小時;
let the_earliest_limitTime_secondes = this.getLimitTimeToSeconds()
if(the_currentTime_seconds < the_earliest_limitTime_secondes) {
this.minuteList[j].disabled = true
this.secondList[k].disabled = true
} else {
this.minuteList[j].disabled = false
this.secondList[k].disabled = false
}
if(the_currentTime_seconds >= 24 * 60 * 60) {
this.minuteList[j].disabled = true
this.secondList[k].disabled = true
}
}
}
break
}
}
}
}
}
</script>
<style lang="stylus" scoped>
.el-time-spinner__wrapper {
width: 33.3%;
}
</style>