使用vue,来写个时间轴

功能

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容