Vue + 原生CSS3 实现像视频时间点在时间轴上效果并且可移动

<template>
  <div class="timeSwiper">
    <div class="time-box">
      <div class="time-title">时间</div>
      <div class="tool-left" @click="reduceYear(nowYear)">
        <span class="icon iconfont">&#xe654;</span>
        <div class="icontime">{{ nowYear }}</div>
      </div>
      <div id="time-lineST">
        <div
          class="keyItemBoxST"
          v-for="(item, __index) of timeKeyWordlist"
          :key="__index"
          :style="getStyle(__index)"
          @click="changeVideoTime(__index)"
        >
          <div v-if="__index == theindex" class="keyitemtitle">
            {{ item.image_time.substr(0, 10) }}
          </div>
        </div>
        <div id="changiconST" :style="getIconX()">
          <div id="VerticalST"></div>
          <div id="triangleST"></div>
        </div>
      </div>
      <div class="tool-right" @click="addYear(nextYear)">
        <span class="icon iconfont">&#xe652;</span>
        <div class="icontime">{{ nextYear }}</div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  props: ["_map"],
  data() {
    return {
      keyX: [], //关键词时间坐标
      timeKeyWordlist: [],
      timeKeyWordlistALL: [
        {
          image_time: "2019-01-15",
        },
        {
          image_time: "2019-02-05",
        },
        {
          image_time: "2019-04-20",
        },
        {
          image_time: "2019-06-28",
        },
        {
          image_time: "2019-11-09",
        },
        {
          image_time: "2020-01-15",
        },
        {
          image_time: "2020-02-10",
        },
        {
          image_time: "2020-08-07",
        },
        {
          image_time: "2020-08-12",
        },
        {
          image_time: "2020-11-05",
        },
        {
          image_time: "2021-11-23",
        },
        {
          image_time: "2020-12-21",
        },
        {
          image_time: "2021-07-05",
        },
        {
          image_time: "2021-09-05",
        },
        {
          image_time: "2021-10-05",
        },
        {
          image_time: "2021-12-05",
        },
      ],
      theindex: 0,
      nextYear: null,
      nowYear: null,
      timeAll: 0,
    };
  },
  watch: {
    timeleft() {
      this.getIconX();
    },
    theindex() {
      console.log(this.theindex, "theindex");
    },
  },
  methods: {
    getlist() {
      this.timeKeyWordlistALL = this.timeKeyWordlistALL.sort(function (a, b) {
        return a.image_time < b.image_time ? 1 : -1;
      });
      this.timeKeyWordlist = [];
      this.timeKeyWordlist = this.timeKeyWordlistALL.filter(
        (val) => val.image_time.indexOf(this.nowYear) > -1
      );
      this.$nextTick(() => {
        this.computeX();
      });
    },
    //利用translateX实现X坐标的移动
    getStyle(__index) {
      if (this.keyX && this.keyX.length > 0 && this.keyX[__index]) {
        let value = this.keyX[__index].transform;
        return "transform: translateX(" + value + "px)";
      } else {
        return "transform: translateX(" + 0 + "px)";
      }
    },
    //利用translateX实现按钮的移动
    getIconX() {
      this.$nextTick(() => {
        if (
          this.keyX.length > 0 &&
          this.theindex != -1 &&
          document.getElementsByClassName("keyItemBoxST").length != 0
        ) {
          let value =
            document
              .getElementsByClassName("keyItemBoxST")
              [this.theindex].getBoundingClientRect().left -
            document.querySelector("#time-lineST").getBoundingClientRect().left;
          document.getElementById("changiconST").style =
            "transform: translateX(" + value + "px)";
        } else {
          document.getElementById("changiconST").style =
            "transform: translateX(" + 0 + "px)";
        }
      });
    },
    // 添加点击时间条
    changeVideoTime(__index) {
      this.theindex = __index;
    },
    // 计算时间轴上时间的位置
    computeX() {
      this.keyX = [];
      let width = document
        .querySelector("#time-lineST")
        .getBoundingClientRect().width;
      //视频进度条像素宽度
      this.timeAll = this.myDate(this.nowYear);
      let time = this.timeKeyWordlist;
      var array = [];
      for (var j = 0; j < time.length; j++) {
        let keyTime = this.getDaysBetween(
          Number(this.nowYear) - 1 + "-12-31",
          time[j].image_time
        );
        let x = (keyTime / this.timeAll) * width;
        //TODO:
        x -=
          j *
          document.querySelector(".keyItemBoxST").getBoundingClientRect().width;
        array.push({
          title: time[j].image_time,
          transform: x, //时间占总时间的比例*位置
        });
        this.keyX = array; //二维数组
        this.theindex = 0;
      }
      this.scale();
    },
    // 滑动点击事件
    scale() {
      if (this.keyX.length > 0) {
        let self = this;
        let dragDiv = document.getElementById("changiconST");
        let leftX = document
          .querySelector("#time-lineST")
          .getBoundingClientRect().left;
        let rightX = document
          .querySelector("#time-lineST")
          .getBoundingClientRect().right;

        // 鼠标按下事件 处理程序
        let putDown = function (event1) {
          event1.cursor = "grabbing";
          document.onmousemove = function (event2) {
            let value = event2.clientX - leftX;
            if (event2.clientX < leftX) {
              dragDiv.style = "transform: translateX(" + 0 + "px)";
            }
            if (leftX < event2.clientX && event2.clientX < rightX) {
              dragDiv.style = "transform: translateX(" + value + "px)";
            }
            if (event2.clientX > rightX) {
              dragDiv.style =
                "transform: translateX(" +
                document.querySelector("#time-lineST").getBoundingClientRect()
                  .width +
                "px)";
            }
          };
          // 鼠标抬起时,清除绑定在文档上的mousemove和mouseup事件
          // 否则鼠标抬起后还可以继续拖拽方块
          document.onmouseup = function (event3) {
            let value = event3.clientX - leftX;
            if (event3.clientX <= leftX) {
              self.theindex = self.keyX.length - 1;
            }
            if (leftX < event3.clientX && event3.clientX < rightX) {
              let arrr = [];
              self.keyX.forEach((item) => {
                arrr.push(item.transform);
              });
              self.theindex = self.findCloseNum(self.keyX, value);
            }
            if (event3.clientX >= rightX) {
              self.theindex = 0;
            }
            document.onmousemove = null;
            document.onmouseup = null;
            self.timeleft = event3.clientX;
            self.$forceUpdate();
          };
        };
        // 绑定鼠标按下事件
        dragDiv.addEventListener("mousedown", putDown, false);
      }
    },
    // 后一天
    reduceYear(val) {
      var d2 = new Date(val + "-03-1");
      d2.setFullYear(d2.getFullYear() - 1);
      d2.setDate(d2.getDate() - 1);
      this.nowYear = d2.toLocaleString().substr(0, 4);
      this.nextYear = val;
      this.getlist();
    },
    // 前一年
    addYear(val) {
      var d2 = new Date(val + "-03-01");
      d2.setFullYear(d2.getFullYear() + 1);
      d2.setDate(d2.getDate() - 1);
      this.nowYear = val;
      this.nextYear = d2.toLocaleString().substr(0, 4);
      this.getlist();
    },
    //获取指定年的天数
    myDate(t) {
      //t 代表指定的参数
      if (t == null) {
        var Year = new Date().getFullYear(),
          s = 0,
          d; //获取当前年
        for (var i = 1; i < 13; i++) {
          d = new Date(Year, i, 0); //获取某一个月的天数
          s += d.getDate();
        }
        return s;
      } else if (t >= 1970) {
        var Year = new Date().getFullYear(),
          s = 0,
          d;
        for (var i = 1; i < 13; i++) {
          d = new Date(t, i, 0);
          s += d.getDate();
        }
        return s;
      } else {
        return "年份有误";
      }
    },
    // 获取两个日期之间的天数
    getDaysBetween(dateString1, dateString2) {
      var startDate = Date.parse(dateString1);
      var endDate = Date.parse(dateString2);
      var days = (endDate - startDate) / (1 * 24 * 60 * 60 * 1000);
      // alert(days);
      return days;
    },
    // 初始获取当前年
    getYear() {
      let date = new Date();
      this.nowYear = date.getFullYear();
      this.nextYear = date.getFullYear() + 1;
      // this.nowYear = 2020;
      // this.nextYear = 2021;
    },

    // 查找最接近数值在数组中的索引
    findCloseNum(arr, num) {
      var index = 0; // 保存最接近数值在数组中的索引
      var d_value = Number.MAX_VALUE; // 保存差值绝对值,默认为最大数值
      for (var i = 0; i < arr.length; i++) {
        // var new_d_value = Math.abs(Number(arr[i].transform) - num); // 新差值
        //TODO:
        var new_d_value = Math.abs(
          Number(arr[i].transform) -
            num +
            i *
              document.querySelector(".keyItemBoxST").getBoundingClientRect()
                .width
        ); // 新差值
        if (new_d_value <= d_value) {
          // 如果新差值绝对值小于等于旧差值绝对值,保存新差值绝对值和索引
          if (
            new_d_value === d_value &&
            Number(arr[i].transform) < Number(arr[index].transform)
          ) {
            // 如果数组中两个数值跟目标数值差值一样,取大
            continue;
          }
          index = i;
          d_value = new_d_value;
        }
      }
      return index; // 返回最接近的数值
    },
  },
  mounted() {
    this.getYear();
    let self = this;
    window.onresize = () => {
      return (() => {
        self.getYear();
      })();
    };
    this.getlist();
  },
};
</script>
<style scoped>
.timeSwiper {
  position: absolute;
  top: 30px;
  left: 620px;
  z-index: 1;
  cursor: pointer;
}
.time-box {
  height: 70px;
  background: rgba(33, 43, 53, 0.8);
  border-radius: 6px;
  color: #cacfd3;
  display: flex;
  padding: 18px;
  -moz-user-select: none;
  /* Firefox */
  -webkit-user-select: none;
  /* WebKit */
  -ms-user-select: none;
  /* IE */
  -khtml-user-select: none;
  /* KHTML */
  -o-user-select: none;
  /* Opera */
  user-select: none;
  /* CSS3属性 */
}
.time-title {
  font-size: 14px;
  color: #ffffff;
  line-height: 28px;
  margin-right: 10px;
}
.tool-left,
.tool-right {
  font-size: 12px;
  color: #ffffff;
  line-height: 20px;
  text-align: center;
  margin: 5px 2px;
  z-index: 99;
}
.icontime {
  font-size: 12px;
}
.tool-edit {
  color: #ffffff;
  font-size: 18px;
  margin-left: 10px;
  margin-top: 3px;
  z-index: 10;
}
#time-lineST {
  width: 220px;
  height: 8px;
  background: rgba(33, 43, 53, 0.5);
  border-radius: 4px;
  margin: 14px 10px;
  box-sizing: content-box;
}
.keyItemBoxST {
  height: 100%;
  width: 1px;
  background: #33ce95;
  cursor: pointer;
  float: left;
}
.keyitemtitle {
  position: relative;
  width: 100px;
  text-align: center;
  top: -23px;
  right: 50px;
  font-size: 12px;
  line-height: 14px;
  display: table;
  color: #fff;
}
#changiconST {
  margin-top: -5px;
}
#triangleST {
  width: 0;
  height: 0;
  border-left: 7px solid transparent;
  border-right: 7px solid transparent;
  border-bottom: 14px solid #ffffff;
  position: relative;
  left: -6.8px;
}
#triangleST:before {
  box-sizing: content-box;
  width: 0;
  height: 0;
  position: relative;
  top: 2px;
  right: 5px;
  padding: 0;
  display: block;
  content: "";
  z-index: 12;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-bottom: 10px solid #33ce95;
}
#VerticalST {
  width: 1px;
  height: 18px;
  background: #fff;
}
</style>

参考文档:https://blog.csdn.net/wantingtr/article/details/87934823

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

侧耳倾听...

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值