vue3 通过使用el-slider制作可自动播放并可以获取当前播放位置值的时间轴。

直接创建timeLine.vue 文件,将代码复制进去即可。(css引用的播放和切换按钮自行修改)

<template>
  <div class="timeLineBox" :style="{ width: prop.step * prop.itemMargin + '%' }">
    <div class="control">
      <div @click="doPrev"></div>
      <div :class="{ stop: isStart }" @click="doPlay"></div>
      <div @click="doNext"></div>
    </div>
    <div class="timeLine">
      <el-slider
        :format-tooltip="formatToolTip"
        @change="sliderChange"
        v-model="value"
        :marks="marks"
        :max="max"
      />
    </div>
  </div>
</template>

<script lang="ts" setup>
/**
 * 使用方法
 * @param {Array} timeLineData 时间轴需要展示的时间数组
 * @param {Number} step 时间轴每一页展示多少个
 * @param {Number} itemMargin 每一页中每个时间点相距距离
 * stopPlay   外部调用停止时间轴方法
 * getCurrentIndex 在外部可以获取到当前播放的时间值
 */
import { ref, onMounted, watch } from "vue";
let prop = defineProps(["timelineData", "step", "itemMargin"]);
const emit = defineEmits(["getCurrentIndex"]);
let value = ref(0);
let max = ref(0);
let isStart = ref(false);
let timmer = ref();
let marks = ref({});
// 多少个时间点
let length = ref();
// 当前下标
let current = ref(0);
// 一页显示7个
let size = ref(7);
// 当前页数
let currentPage = ref(1);
// 总页数
let totalPage = ref(1);
// 当前页有几个时间点
let currentNums = ref();
//用来存 指定显示 那个时间点
let zdNowIdx = ref("");
onMounted(() => {
  init();
  start();
});
const doPlay = () => {
  isStart.value = !isStart.value;
  start();
};
// 停止播放
const stopPlay = () => {
  isStart.value = false;
  start();
};
const doPrev = () => {
  if (current.value === 0) {
    current.value = 0;
    value.value = 0;
  } else {
    current.value--;
    value.value--;
  }

  emit("getCurrentIndex", marks.value[current.value]);
  isStart.value = false;
  start();
};
const doNext = () => {
  if (current.value === currentNums.value - 1) {
    value.value = current.value;
  } else {
    current.value++;
    value.value++;
  }
  emit("getCurrentIndex", marks.value[current.value]);
  isStart.value = false;
  start();
};
const sliderChange = (v) => {
  current.value = v;
  emit("getCurrentIndex", marks.value[current.value]);
  isStart.value = false;
  start();
};
const formatToolTip = (v) => {
  if (marks.value[v]) {
    return marks.value[v].label;
  }
};
const init = () => {
  // slider个数,0也算 所以-1
  size.value = prop.step;
  max.value = size.value - 1;
  length.value = prop.timelineData.length;
  // 得出总页数
  if (length.value % size.value === 0) {
    totalPage.value = length.value / max.value;
  } else {
    totalPage.value = Math.ceil(length.value / max.value);
  }

  let obj = {};
  if (length.value > size.value) {
    prop.timelineData
      .slice((currentPage.value - 1) * size.value, size.value * currentPage.value)
      .forEach((item, index) => {
        obj[index] = { label: item.name, value: item.value };
      });
    // 当前页有几个时间段
    currentNums.value = prop.timelineData.slice(
      (currentPage.value - 1) * size.value,
      size.value * currentPage.value
    ).length;
  } else {
    prop.timelineData.forEach((item, index) => {
      obj[index] = { label: item.name, value: item.value };
    });
    // 当前页有几个时间段
    currentNums.value = prop.timelineData.length;
  }

  marks.value = obj;
};
let start = () => {
  if (isStart.value) {
    clearInterval(timmer.value);
    timmer.value = null;
    timmer.value = setInterval(() => {
      if (current.value > currentNums.value - 1) {
        current.value = 0;
        // 总页数大于1的话说明要走分页 第二页操作

        if (totalPage.value > 1) {
          currentPage.value++;
          // 当前页大于总页数的话说明 当前页该显示第一页 了
          if (currentPage.value > totalPage.value) {
            currentPage.value = 1;
          }
          getFormatData();
        }
      }

      emit("getCurrentIndex", marks.value[current.value]);
      // ++之前返回的是当前时间轴显示的日期数据
      value.value = current.value++;
    }, 1000);
  } else {
    clearInterval(timmer.value);
    timmer.value = null;
  }
};
const getFormatData = () => {
  let obj = {};
  prop.timelineData
    .slice((currentPage.value - 1) * size.value, size.value * currentPage.value)
    .forEach((item, index) => {
      obj[index] = { label: item.name, value: item.value };
    });

  // 当前页有几个时间段
  currentNums.value = prop.timelineData.slice(
    (currentPage.value - 1) * size.value,
    size.value * currentPage.value
  ).length;
  max.value = currentNums.value - 1;
  marks.value = obj;
};
// 设置默认进来的下标; 设置变量存起来,在watch中设置。因为当前方法获取到的是timelinedata未改变之前的数据
const initCurrentIndex = (v) => {
  zdNowIdx.value = v;
  let idx = prop.timelineData.findIndex((item) => item.name === v);

  value.value = idx;
  current.value = idx;
};

watch(
  () => prop.timelineData,
  (newVal, oldVal) => {
    init();
    initCurrentIndex(zdNowIdx.value);
  }
);
defineExpose({
  stopPlay,
  initCurrentIndex,
});
</script>
<style lang="scss" scoped>
.stop {
  background: url("@/assets/images/oneMap/stop.png") no-repeat !important;
  background-size: 100% 100%;
}
:deep(.el-slider__marks-text) {
  background: rgba(255, 255, 255, 0.16);
  border-radius: 3px 3px 3px 3px;
  opacity: 1;
  font-size: 12px;
  padding: 5px;
  font-family: PingFang SC-Regular, PingFang SC;
  font-weight: 400;
  color: #ffffff;
  line-height: 16px;
}
.timeLineBox {
  position: absolute;
  bottom: 20px;
  height: 56px;
  width: 528px;
  left: 52%;
  transform: translateX(-50%);
  background: rgba(34, 79, 141, 0.64);
  box-shadow: inset 0px 0px 14px 0px rgba(72, 254, 254, 0.4);
  border-radius: 4px 4px 4px 4px;
  opacity: 1;
  border: 1px solid rgba(255, 255, 255, 0.08);
  display: flex;
  .control {
    display: flex;
    align-items: center;
    justify-content: space-around;
    width: 108px;
    height: 100%;
    background: rgba(0, 0, 0, 0.3);
    border-radius: 4px 0px 0px 4px;
    opacity: 1;
    border: 1px solid;
    border-image: linear-gradient(180deg, rgba(70, 132, 255, 1), rgba(82, 138, 250, 0.48))
      1 1;
    div {
      cursor: pointer;
      width: 28px;
      height: 28px;
      background-color: pink;
      &:nth-child(1) {
        background: url("@/assets/images/oneMap/prev.png") no-repeat;
        background-size: 100% 100%;
      }
      &:nth-child(2) {
        background: url("@/assets/images/oneMap/start.png") no-repeat;
        background-size: 100% 100%;
      }
      &:nth-child(3) {
        background: url("@/assets/images/oneMap/next.png") no-repeat;
        background-size: 100% 100%;
      }
    }
  }
  .timeLine {
    flex: 1;
    background: rgba(34, 79, 141, 0.64);
    box-shadow: inset 0px 0px 14px 0px rgba(72, 254, 254, 0.4);
    opacity: 1;
    border: 1px solid rgba(255, 255, 255, 0.08);
    padding: 31px;
    padding-top: 0;
  }
}
</style>

父组件调用如下。传入的参数使用含义在上面的时间轴代码中有注释

效果如下。

如果当前返回的值和时间轴不匹配的话,将initCurrentIndex方法注释掉试一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值