时间轴组件开发:实现灵活的时间范围选择

前言

前端开发中,时间范围选择是一个非常常见的功能需求,无论是数据统计还是订单筛选,都离不开它。虽然 element 组件库提供的基础日期选择器能够满足大部分常规需求,但当项目出现 「动态时间推移」「时间间隔自定义」 等定制化需求时,原生组件便显得捉襟见肘。本文将实现自定义的时间范围选择组件,不仅支持自定义时间区间的选择,还能根据用户设置的时间间隔,实现向前、向后推移时间范围的交互功能。


一、完整代码

html 复制代码
<template>
  <div class="timeline">
    <div>
      <el-date-picker v-model="dateData" :picker-options="pickerOptions" value-format="yyyy-MM-dd HH:mm:ss" type="datetimerange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="defaultTime" @change="timeChange"> </el-date-picker>
    </div>
    <div>
      <el-select v-model="interval" placeholder="请选择间隔时间">
        <el-option v-for="item in optionsInterval" :key="item.value" :label="item.label" :value="item.value"> </el-option>
      </el-select>
    </div>
    <div>
      <el-tooltip class="item" effect="dark" :content="'时间向前' + interval + '小时'" placement="top-start">
        <svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" version="1.1" width="63px" height="40px" class="leftArrow" @click="front">
          <g transform="matrix(1 0 0 1 -562 -494 )">
            <path d="M 593 529.4  L 609 514  L 593 498.6  L 593 529.4  Z " fill-rule="nonzero" fill="#70b603" stroke="none" />
            <path d="M 566 514  L 597 514  " stroke-width="8" stroke="#70b603" fill="none" />
          </g>
        </svg>
      </el-tooltip>
      <el-tooltip class="item" effect="dark" :content="'时间向后' + interval + '小时'" lacement="top-start">
        <svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" version="1.1" width="63px" height="40px" @click="offspring">
          <g transform="matrix(1 0 0 1 -562 -494 )">
            <path d="M 593 529.4  L 609 514  L 593 498.6  L 593 529.4  Z " fill-rule="nonzero" fill="#70b603" stroke="none" />
            <path d="M 566 514  L 597 514  " stroke-width="8" stroke="#70b603" fill="none" />
          </g>
        </svg>
      </el-tooltip>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    const initialDateData = ["2022-02-01 15:20:30", "2022-02-04 12:30:00"]; // 初始化初始日期范围
    return {
      defaultTime: ["00:00:00", "23:59:59"],
      dateData: [...initialDateData], // 当前日期范围,初始值为初始日期范围的副本
      initialDateData, // 存储初始日期范围,用于后续比较
      currentDateData: [...initialDateData], // 当前操作的日期范围,初始值为初始日期范围的副本
      pickerOptions: {
        disabledDate: (time) => {
          const start = new Date(this.initialDateData[0]).getTime();
          const end = new Date(this.initialDateData[1]).getTime();
          return time.getTime() < start || time.getTime() > end;
        },
      },
      interval: "1",
      optionsInterval: [
        {
          value: "1",
          label: "1小时",
        },
        {
          value: "3",
          label: "3小时",
        },
        {
          value: "5",
          label: "5小时",
        },
        {
          value: "7",
          label: "7小时",
        },
      ],
    };
  },
  methods: {
    // 日期范围选择变化时的回调函数
    timeChange(newValue) {
      // 更新当前操作的日期范围为新选择的日期范围
      this.currentDateData = newValue;
    },
    // 向前操作的方法
    front() {
      // 获取当前操作日期范围的结束时间
      const currentEndTime = new Date(this.currentDateData[1]);
      // 计算新的结束时间,通过当前结束时间减去所选间隔小时数
      const newEndTime = new Date(currentEndTime.getTime() - parseInt(this.interval) * 60 * 60 * 1000);
      // 获取初始日期范围的开始时间
      const initialStartTime = new Date(this.initialDateData[0]);
      // 检查新的结束时间是否大于等于初始开始时间
      if (newEndTime >= initialStartTime) {
        // 计算新的开始时间,通过新的结束时间减去所选间隔小时数
        const newStartTime = new Date(newEndTime.getTime() - parseInt(this.interval) * 60 * 60 * 1000);
        // 更新当前操作的日期范围,确保新的开始时间不小于初始开始时间
        this.currentDateData = [this.formatDate(newStartTime >= initialStartTime ? newStartTime : initialStartTime), this.formatDate(newEndTime)];
        // 同步更新显示的日期范围
        this.dateData = [...this.currentDateData];
      } else {
        // 若超出范围,给出警告提示
        this.$message.warning("向前操作超出了初始时间范围!");
      }
    },
    // 向后操作的方法
    offspring() {
      // 获取当前操作日期范围的开始时间
      const currentStartTime = new Date(this.currentDateData[0]);
      // 计算新的开始时间,通过当前开始时间加上所选间隔小时数
      const newStartTime = new Date(currentStartTime.getTime() + parseInt(this.interval) * 60 * 60 * 1000);
      // 获取初始日期范围的结束时间
      const initialEndTime = new Date(this.initialDateData[1]);
      // 检查新的开始时间是否小于等于初始结束时间
      if (newStartTime <= initialEndTime) {
        // 计算新的结束时间,通过新的开始时间加上所选间隔小时数
        const newEndTime = new Date(newStartTime.getTime() + parseInt(this.interval) * 60 * 60 * 1000);
        // 更新当前操作的日期范围,确保新的结束时间不大于初始结束时间
        this.currentDateData = [this.formatDate(newStartTime), this.formatDate(newEndTime <= initialEndTime ? newEndTime : initialEndTime)];
        // 同步更新显示的日期范围
        this.dateData = [...this.currentDateData];
      } else {
        // 若超出范围,给出警告提示
        this.$message.warning("向后操作超出了初始时间范围!");
      }
    },
    // 日期格式化方法,将 Date 对象转换为指定格式的字符串
    formatDate(date) {
      // 获取年份
      const year = date.getFullYear();
      // 获取月份、日、小时、分钟、秒并补零
      const month = String(date.getMonth() + 1).padStart(2, "0");
      const day = String(date.getDate()).padStart(2, "0");
      const hours = String(date.getHours()).padStart(2, "0");
      const minutes = String(date.getMinutes()).padStart(2, "0");
      const seconds = String(date.getSeconds()).padStart(2, "0");
      // 返回格式化后的日期字符串
      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
    },
  },
};
</script>

<style scoped>
.timeline {
  padding: 20px;
  display: flex;
}
.timeline div {
  margin-right: 5px;
}
.leftArrow {
  transform: rotate(180deg);
}
svg {
  cursor: pointer;
}
</style>

二、实现思路

  • 模板部分 <template>

    包含日期范围选择器,一个间隔时间选择下拉框,两个 el-tooltip 组件,分别包含一个 SVG 图标,用于时间向前和向后操作,分别绑定了 frontoffspring 方法;

  • 数据部分 data

    变量 描述
    defaultTime 设置日期选择器的默认时间范围为一天(从 00:00:00 到 23:59:59)
    dateData 当前显示的日期范围,初始值为 initialDateData 的副本
    initialDateData 存储初始日期范围,用于限制可选日期范围
    currentDateData 当前操作的日期范围,初始值为 initialDateData 的副本
    pickerOptions 日期选择器的选项,通过 disabledDate 方法限制可选日期范围在 initialDateData 之内
    interval 当前选择的间隔时间,默认值为 '1'
    optionsInterval 间隔时间选择下拉框的选项数组
  • 方法部分 methods

    方法名 描述
    timeChange 当日期范围选择变化时的回调函数,更新 currentDateData 为新选择的日期范围
    front 时间向前操作的方法,计算新的结束时间和开始时间,检查是否在初始时间范围内,更新 currentDateData 和 dateData,若超出范围则给出警告提示
    offspring 时间向后操作的方法,计算新的开始时间和结束时间,检查是否在初始时间范围内,更新 currentDateData 和 dateData,若超出范围则给出警告提示
    formatDate 日期格式化方法,将 Date 对象转换为指定格式的字符串
  • 样式部分 style

    定义了 .timeline 类的样式,设置宽度、内边距、显示方式和子元素的间距。

    定义了 .leftArrow 类的样式,将 SVG 图标旋转 180 度。

    定义了 svg 元素的样式,设置鼠标指针为指针样式。

通过以上实现思路,就可以满足日期范围选择、间隔时间选择以及时间向前和向后操作的功能,并在操作过程中进行时间范围的限制和提示。


三、实现效果


相关推荐

element 日期组件使用技巧:时间范围选择限制

element日期选择器掌控时间范围,更好地满足你的需求

element日期组件新玩法:只选小时或小时、分钟,让时间更精准

解决element日期组件清空后的报错,让你的页面不再崩溃

相关推荐
前端大卫4 小时前
Vue 和 React 受控组件的区别!
前端
Hy行者勇哥4 小时前
前端代码结构详解
前端
练习时长一年5 小时前
Spring代理的特点
java·前端·spring
2501_930124706 小时前
Linux之Shell编程(三)流程控制
linux·前端·chrome
潘小安6 小时前
『译』React useEffect:早知道这些调试技巧就好了
前端·react.js·面试
@大迁世界6 小时前
告别 React 中丑陋的导入路径,借助 Vite 的魔法
前端·javascript·react.js·前端框架·ecmascript
EndingCoder6 小时前
Electron Fiddle:快速实验与原型开发
前端·javascript·electron·前端框架
EndingCoder6 小时前
Electron 进程模型:主进程与渲染进程详解
前端·javascript·electron·前端框架
Nicholas687 小时前
flutter滚动视图之ScrollNotificationObserve源码解析(十)
前端