效果
<template>
<div class="time-picker" id="time-picker" v-click-outside="handleClose">
<Input
:readonly="true"
:value="backfillText"
@click.native="handleOpen"
>
<i slot="prefix" class="iconfont icon-ico_date"></i>
</Input>
<div class="dropdown-con" v-show="visible">
<div class="header-title">
<span>开始</span>
<span></span>
<span>结束</span>
</div>
<div class="time-range-con" id="time-range-con">
<ul id="range-con" class="range-con" ref="hours">
<li
v-for="(item, index) in hoursList"
:key="index"
:class="item.value === startTime ? 'active-cell' : ''"
@click="handleClick(item)"
>
{
{
formatTime(item.label)}}
</li>
</ul>
<div>
<i class="iconfont icon-ico_arrow"></i>
</div>
<ul id="range-con" class="range-con" ref="hoursEnd">
<li
v-for="(item,index) in hoursList"
:key="index"
:class="item.value === endTime ? 'active-cell' : ''"
@click="handleClickEnd(item)"
>
{
{
formatTime(item.label)}}
</li>
</ul>
</div>
</div>
</div>
</template>
<script>
import moment from 'moment';
let hoursList = [];
for(let i = 0; i <=24; i++) {
hoursList.push({
label: i,
value: i
});
}
export default {
name: 'timePicker',
props: {
value: {
type: Array,
default: () => ['0:00','24:00']
}
},
data() {
return {
visible: false,
hoursList: hoursList,
startTime: '',
endTime: ''
};
},
created() {
},
computed: {
backfillText() {
let dates = [];
dates[0] = `${
this.formatTime(this.startTime)}:00`;
dates[1] = `${
this.formatTime(this.endTime)}:00`;
this.$emit('input', dates);
return `${
this.formatTime(this.startTime)}:00 - ${
this.formatTime(this.endTime)}:00`;
}
},
watch: {
value: {
handler(newVal, oldVal) {
const [startTime, endTime] = newVal.slice();
this.startTime = Number(startTime.split(':')[0]) || 0;
this.endTime = Number(endTime.split(':')[0]) || 0;
},
immediate: true,
},
startTime(newVal, oldVal) {
this.scroll('hours', newVal, oldVal);
},
endTime(newVal, oldVal) {
this.scroll('hoursEnd',newVal, oldVal);
}
},
methods: {
scroll(type, newVal, oldVal) {
const from = oldVal * 20; //每个时间的高度20px
const to = newVal * 20;
this.$nextTick(() => {
this.scrollTop(this.$refs[type], from, to);
})
},
/**
* 点击或该开始进入 内容出现在第一个
*/
scrollTop(el, from = 0, to, duration = 500, endCallback) {
if (!window.requestAnimationFrame) {
window.requestAnimationFrame =
window.webkitRequestAnimationFrame ||
function(callback) {
return window.setTimeout(callback, 1000 / 60);
};
}
const difference = Math.abs(from - to);
const step = Math.ceil((difference / duration) * 50);
function scroll(start, end, step) {
if (start === end) {
endCallback && endCallback();
return;
}
let d = start + step > end ? end : start + step;
if (start > end) {
d = start - step < end ? end : start - step;
}
if (el === window) {
window.scrollTo(d, d);
} else {
el.scrollTop = d;
}
window.requestAnimationFrame(() => scroll(d, end, step));
}
scroll(from, to, step);
},
/**
* 打开 选择时间
*/
handleOpen() {
this.visible = true;
this.scroll('hours', this.startTime, 0);
this.scroll('hoursEnd', this.endTime, 0);
},
/**
* 0补齐
*/
formatTime(text) {
return text < 10 ? '0' + text : text;
},
/**
* 点击旁边的内容 弹窗关闭
*/
handleClose() {
this.visible = false;
},
/**
* 选择开始时间
*/
handleClick(item) {
this.startTime = item.value;
if(!this.endTime || this.endTime < this.startTime) {
this.endTime = this.startTime;
}
},
/**
* 选择结束时间
*/
handleClickEnd(item) {
if(item.value < this.startTime) {
return;
}
this.endTime = item.value;
}
},
};
</script>
<style scoped lang="scss">
/*其它所有滚动条样式*/
#range-con::-webkit-scrollbar {
/*滚动条整体样式*/
width: 4px;
/*高宽分别对应横竖滚动条的尺寸*/
height: 0;
}
#range-con::-webkit-scrollbar-thumb {
/*滚动条里面小方块*/
border-radius: 2px;
background: rgba(191, 191, 191, 1);
}
#range-con::-webkit-scrollbar-track {
/*滚动条里面轨道*/
border-radius: 0;
background: #fff;
}
.time-picker {
position: relative;
}
.dropdown-con {
width: 190px;
max-height: 200px;
overflow: auto;
z-index: 100;
margin: 5px 0;
position: absolute;
background-color: #fff;
border-radius: 4px;
-webkit-box-shadow: 0 1px 6px rgba(0, 0, 0, 0.2);
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.2);
.header-title {
display: flex;
padding: 13px;
font-size: 12px;
border-bottom: 1px solid #e8eaec;
& > span {
flex: 1;
text-align: left;
}
}
}
.time-range-con {
display: flex;
position: relative;
&::after {
content: '';
display: block;
position: absolute;
background: #e8eaec;
width: 4px;
transform: translateX(-50%);
top: 0px;
bottom: 0px;
}
& > ul {
height: 150px;
flex: 2;
overflow-y: hidden;
&:hover {
overflow-y: auto;
}
& > li {
font-size: 12px;
padding-left: 15px;
height: 20px;
line-height: 20px;
cursor: pointer;
&:hover {
color: #f90;
background: #f3f3f3;
}
}
}
& > div {
flex: 1;
// justify-content: center;
// align-items: center;
text-align: center;
padding-top: 50px;
border-left: 1px solid #e3e3e3;
border-right: 1px solid #e3e3e3;
}
.active-cell {
color: #f90;
background: #f3f3f3;
}
}
</style>
引用
<time-picker class="mar-left" v-model="hourValue"></time-picker>
hourValue: ['09:00','23:00'],