功能
1.选择时间,获取对应数据,显示时间轴和时间点
2.时间点hover显示对应时间
3.整点时间显示
4.点击时间轴,选择对应的时间点
5.点击时间点,选择对应的时间点
6.拖动点,选择对应的时间点
7.限制拖动,及点击位置
效果图
组件代码
1.框架:vue+axios
2.日期组件:Ant Design of Vue(也可以自己修改成其他日期组件)
3.日期格式化:moment
安装:
npm i moment --save-dev
---------------------------------------
main.js引入:
//引入moment
import moment from 'moment'
import 'moment/locale/zh-cn'//中文
Vue.prototype.$moment = moment
---------------------------------------
vue文件中:
let createDate =this.$moment(value).format('YYYY/MM/DD');
4.数据返回格式
tips:数据返回为时间戳秒钟算,而不是毫秒,所以有些地方需要*1000计算
<template>
<div class="time_con">
<span>选择显示区间:</span>
<a-date-picker
v-model="startValue"
format="YYYY-MM-DD"
placeholder="开始时间"
@openChange="handleStartOpenChange"
:disabled-date="disabledStartDate"
@change="changePicker"
size="large"
/>
<a-date-picker
v-model="endValue"
format="YYYY-MM-DD"
placeholder="结束时间"
:open="endOpen"
@openChange="handleEndOpenChange"
:disabled-date="disabledEndDate"
@change="changePicker"
size="large"
/>
<div class="line_time" v-show="showLine">
<div class="all_line" @mousedown.stop="lineMouseDown">
<!-- <div class="all_line"> -->
<div class="line" ref="allLineTime">
<!-- 可以滑动的线 -->
<div class="can_line" ref="canLine" @mousedown.stop="canLineMouseDown"></div>
<!-- 参考点 -->
<div class=" reference" v-for="(dateTip,dt) in dateTips" :key="'tips-'+dt" :style="setLeft(dateTip)">
<em v-text="formatter(dateTip,1)" ></em>
</div>
<!-- 备份点 -->
<div class="dot dot_all" v-for="(incre,i) in incre_dates" :key="i" :style="setLeft(incre)" @mousedown.stop="clickDot(incre)">
<em v-text="formatter(incre)" ></em>
</div>
<!-- 可滑动点 -->
<div class="dot sel_dot" ref="selDot" @mousedown.stop="dragDown">
<em>{{selTime}}<i></i></em>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import {getBackupTimeline} from "@/plugins/axios";
export default {
name: "TimeLine",
data() {
return {
startValue: this.$moment().format("YYYY-MM-DD"),//开始时间---时间选择
endValue: this.$moment().format("YYYY-MM-DD"),//结束时间---时间选择
endOpen: false,
fullDate:null,//最初时间(最开始有数据的时候)
binlogDate:null,//binlog 结束时间
selTime:null,//选中时间
start_date:null,//开始时间戳
end_date:null,//结束时间戳
timeline:null,//选中时间戳
incre_dates:[],//备份点数组
allIncre:[],//备份点和binlog
showLine:false,//是否显示时间轴
dateTips:[],//0点,提示时间点数组
};
},
created(){
let today = new Date();
let forToday = this.$moment(today).subtract(7, 'd');//获取七天前的日期
this.startValue = this.$moment(forToday).startOf('day').format("YYYY-MM-DD");//默认设置七天前的0点为开始时间
this.endValue = this.$moment(today).endOf('day').format("YYYY-MM-DD");//默认设置今天为结束时间
this.getBackupTimeline(1);//参数1表示第一次执行
},
mounted() {
},
methods: {
//时间显示格式
formatter(value,day) {
if(day)return `${this.$moment(value*1000).format('YYYY/MM/DD')}`;
return `${this.$moment(value*1000).format('YYYY/MM/DD HH:mm:ss')}`;
},
//开始时间---范围
disabledStartDate(startValue) {
let today = new Date();
if(this.endValue){
return startValue.format("X")*1 > this.$moment(this.endValue).endOf('day').format("X")*1 || startValue.endOf('day').format("X")*1 < this.fullDate*1;
}else{
return startValue.format("X")*1 > this.$moment(today).endOf('day').format("X")*1 || startValue.format("X")*1 < this.fullDate*1;
}
},
//结束时间---范围
disabledEndDate(endValue) {
const startValue = this.startValue;
let today = new Date();
if(startValue){
let eDate = this.$moment(startValue).add(7, 'd');
return endValue.format("X")*1 > eDate.format("X")*1 || endValue.format("X")*1 < this.$moment(startValue).startOf('day').format("X")*1 || endValue.format("X")*1 > this.$moment(today).format("X")*1;
}else{
return endValue.format("X")*1 < this.fullDate || endValue.format("X")*1 > this.$moment(today).format("X")*1;
}
},
handleStartOpenChange(open) {
if (!open) {
this.endOpen = true;
}
},
handleEndOpenChange(open) {
this.endOpen = open;
},
//时间选择---修改时间
changePicker(){
if(this.startValue && this.endValue){
this.getBackupTimeline();
}
},
//获取时间轴数据
getBackupTimeline(n){
if(!n)this.showLine = true;//首次执行,不显示时间轴,只用于获取fullDate和binlogDate
this.$parent.showLine = false;
this.start_date = this.$moment(this.startValue).startOf('day').format("X")*1;
this.end_date = this.$moment(this.endValue).endOf('day').format("X")*1;
//请求参数
let params={
bak_db_id:this.$route.query.bak_db_id,
start_date:this.start_date,
end_date:this.end_date,
}
getBackupTimeline(params).then(r=>{
if(r.data.status==2000){//请求成功
let dt = r.data.data;
this.fullDate = dt.full_date;
this.binlogDate = dt.binlog_date;
if(n){//首次执行,获取可选择日期
let today = new Date();
let forToday = this.$moment(today).subtract(7, 'd');
if(this.$moment(forToday).format('X')<this.fullDate*1){//若可选择日期大于七天前,则重新设置开始时间
this.startValue = this.$moment(this.fullDate*1000).startOf('day').format("YYYY-MM-DD");
this.start_date = this.$moment(this.startValue).startOf('day').format("X")*1;
this.getBackupTimeline();
return false
}
}
//设置binlog
let canLine = this.$refs.canLine;
let binlogStart=this.start_date>this.fullDate?this.start_date:this.fullDate;//binlog开始时间
let binlogNum = (this.binlogDate-binlogStart)/(this.end_date-this.start_date);//binlog占时间轴百分比
if(binlogNum>0){//如果选择的时间有binlog
canLine.style.width = binlogNum*100 + '%' ;
canLine.style.left = (binlogStart-this.start_date)/(this.end_date-this.start_date)*100 + '%';
canLine.style.maxWidth =100-parseFloat(canLine.style.left) + '%' ;
}else{
canLine.style.width = 0 + '%' ;
if(dt.incre_dates.length<=0){
this.$message.warning('所选时间区间没有可选择时间点,请修改时间区间~');
this.showLine = false;
this.timeline = null;
this.$parent.showLine = true;
}
}
//设置备份时间点数组
this.incre_dates = dt.incre_dates;
this.allIncre = dt.incre_dates.concat([this.binlogDate,this.fullDate]);//备份时间点加上binlog结束时间点和fullDate
this.clickDot(dt.incre_dates[0]);//设置默认选择点
this.timeline = dt.incre_dates[dt.incre_dates.length-1];
//添加提示时间点---0点提示
this.dateTips=[];
let days = Math.abs(this.$moment(this.endValue).endOf('day').diff(this.$moment(this.startValue).startOf('day'), 'days'));
for(let i=0;i<=days;i++){
this.dateTips.push(this.$moment(this.startValue).add(i, 'd').startOf('day').format('X'));
}
}
});
},
//点击时间轴---计算百分比
lineMouseDown(e){
let allLineTime = this.$refs.allLineTime;
let percentNum = (e.offsetX-6)/(allLineTime.offsetWidth*1);
this.setSelTime(percentNum);
},
//可选择线的区域点击
canLineMouseDown(e){
let canLine = this.$refs.canLine;
let allLineTime = this.$refs.allLineTime;
let percentNum = e.offsetX/(allLineTime.offsetWidth*1);
if(parseFloat(canLine.style.left)>0){
percentNum = e.offsetX/(allLineTime.offsetWidth*1)+(parseFloat(canLine.style.left)/100);
}
this.setSelTime(percentNum);
},
//点击备份点---计算百分比
clickDot(incre){
let percentNum = (incre-this.start_date)/(this.end_date-this.start_date);
this.setSelTime(percentNum);
},
//设置当前值
setSelTime(percentNum){
let selDot = this.$refs.selDot;
selDot.classList.remove('sel_dot_left');
selDot.classList.remove('sel_dot_right');
let percent = percentNum;
this.timeline= (this.end_date-this.start_date)*percent+this.start_date;
//如果当前值不在binlog范围内,则不可以滑动,只能选择就近的点
if(this.timeline>this.binlogDate || this.timeline<this.fullDate){
this.allIncre.sort((a,b)=>{
return Math.abs(a-this.timeline)-Math.abs(b-this.timeline);
});
this.timeline = this.allIncre[0];
percent = (this.timeline-this.start_date)/(this.end_date-this.start_date);
}
//设置选中点日期时间
this.selTime = this.$moment(this.timeline*1000).format('YYYY-MM-DD HH:mm:ss');
selDot.style.left = percent*100 + '%' ;
//大于90%或者小于10%,提示框位置变化
if(percent*100<10){
selDot.classList.add('sel_dot_left');
}
if(percent*100>90){
selDot.classList.add('sel_dot_right');
}
},
//时间轴推拽
dragDown(e){
let allLineTimeWidth = this.$refs.allLineTime.offsetWidth*1;
let selDot = this.$refs.selDot;
//算出鼠标相对元素的位置
let disX = e.clientX - selDot.offsetLeft;
document.onmousemove = (e)=>{//鼠标按下并移动的事件
//用鼠标的位置减去鼠标相对元素的位置,得到元素的位置
let left = (e.clientX - disX)/allLineTimeWidth*100;
//移动当前元素
if(left>=100){
left = 100;
}else if(left<=0){
left = 0;
}
this.setSelTime(left/100);
};
document.onmouseup = (e) => {
document.onmousemove = null;
document.onmouseup = null;
};
},
//设置备份点位置
setLeft(incre){
return `left:${(incre-this.start_date)/(this.end_date-this.start_date)*100}%`
},
},
};
</script>
<style lang='scss' scoped>
.time_con{
padding-bottom: 20px;
}
.line_time{
position: relative;
padding: 70px 0 20px;
-webkit-user-select:none;
-moz-user-select:none;
-ms-user-select:none;
user-select:none;
.all_line{
width: 90%;
margin: 0 5%;
padding: 20px 0;
}
.line{
width: 100%;
height: 3px;
background: #ccc;
position: relative;
}
.can_line{
background: #1890ff77;
height: 3px;
width: 20%;
position: absolute;
left: 0;
span{
position: absolute;
right: 0;
margin-top: 20px;
}
}
.reference{
width: 1px;
height: 8px;
border: 0;
background: #bbb;
position: absolute;
top: -3px;
white-space: nowrap;
em{
color: #bbb;
position: absolute;
transform: translateX(-50%);
margin-top: 15px;
font-size: 12px;
}
}
.dot{
width: 8px;
height: 8px;
border-radius: 50%;
border: 2px solid $sel_color;
background: white;
position: absolute;
top: -3px;
white-space: nowrap;
margin-left: -4px;
}
.dot_all{
em{
display: none;
color: $sel_color;
transform: translateX(-50%);
margin-top: 25px;
}
}
.dot_all:hover{
width: 10px;
height: 10px;
border: 2px solid $sel_color;
top: -4px;
em{
display: inline-block;
}
}
.sel_dot{
width: 12px;
height: 12px;
top: -5px;
border: 2px solid $text_yellow;
box-shadow: 0 0 10px 4px #faa30255;
z-index: 5;
position: absolute;
em{
position: absolute;
top: -50px;
border: 1px solid #ccc;
display: inline-block;
padding: 0 20px;
line-height: 26px;
border-radius: 13px;
white-space: nowrap;
transform: translateX(-50%);
color: $text_yellow;
}
i{
contain: '';
border: 1px solid #ccc;
background: white;
width: 10px;
height: 10px;
display: block;
position: absolute;
transform: rotate(45deg);
bottom: -4px;
left: 50%;
border-top: 0;
border-left: 0;
}
}
.sel_dot_left{
em{
transform: translateX(-20%);
}
i{
left: 20%;
}
}
.sel_dot_right{
em{
transform: translateX(-80%);
}
i{
left: 80%;
}
}
}
.ant-calendar-picker{
margin-left: 20px;
}
</style>
转载请著名出处~
-----*13
网友评论