基于Element ui的日期滑块设计

前言

前些时间导师接了一个数字孪生的小项目,让我一个人完成前端三维隧道看板以及填报系统的构建。

技术路线:vue element admin + element ui + arcgis api for javascript。

最近项目接近尾声,我记录一下之前遇到一下项目过程中犯得一个幼稚的错误。

需求

前端实现一个日期滑块,要能选择开始和结束日期,通过滑动日期滑块选择某日期前所有模型的显隐,达到模拟施工进度的效果。

ps:模型属性没日期,需要将日期传给后端,然后后端返回模型的链接以及模型 id。

思路

说多了,继续回到标题。制作一个日期滑块,自然而然地想到了利用 elemnet ui 的datepiker组件和slider组件。Datepiker 负责选择起始日期,然后将选择的日期传给 slider,然后调用 slider 组件的 input 方法,将日期轴上变化的时间传给后端。So easy,看来今天能早点下班。

element-ui-slider组件◎ element-ui-slider组件

element-ui-datepiker组件◎ element-ui-datepiker组件

结果等我想传值的时候,突然发现 slider 的绑定值是 number 类型,但是一年 365 天的日期不连续,甚至偶尔还有 366 天出来捣乱,我该怎么将日期跟 number 关联上?最开始的想法是计算起始日期给和 slider 绑定的 value 计算硬算出当前日期,后来考虑到大小月平闰年的,属实不现实,我直呼做不了。

但是甲方直呼 arcgis api 有现成的sample啊,他们是怎么做到?我看了看确实有时间轴,也确实能过滤要素。但是他的日期是固定的啊,固定的时间轴谁不会啊?甲方表示不听不听,王八念经。

不过能力不够,我很抱歉,只能先做一个可以自由选择起始和终止月份的时间轴先应付着,把别的简单功能先完成,再回头做这个吧。甲方无奈之下,也只能暂时妥协。

按月份做时间轴滑块的思维过程就很流畅了,先计算起始月份和终止月份相差多少个月确定 slider 的最大值,然后根据 slider 的绑定值加上起始月份除以 12 求商并取余就能得到当前绑定值是哪年哪月了。

后来其他需求做的差不多,甲方表示时间轴的精度太低了,这样哪还有施工进度模拟的感觉,一个月有将近三十天,那就每个月取三个日期,1 号,11 号,21 号吧,效果看起来能好点。

啧,感觉他们的需求很合理啊,这么正常的需求我做不出来,肯定是我能力不够,就想去我去网上看看有没有现成的轮子。结果我检索能力也不行,找了一圈没找到合适的。

算了,我自己再想想,顺便去做了个核酸,喉咙被戳得挺不爽的,突然一时就思路清晰了,用时间戳啊,时间戳每天的时长固定的而且能跟日期相互转换。起始日期转为时间戳,然后加上 slider 绑定值的天数的时长,再转换为当前日期就完成了。这么简单的事,我一时居然想不到,果然是我还是经验不够能力不行。

代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// Datepiker
pickDate() {
  if (this.dateselect != []) {
    // Datepiker的绑定值是一个数组,存着起始日期和终止日期
    const startDate = Date.parse(this.dateselect[0])
    const endDate = Date.parse(this.dateselect[1])
    // 计算起始日期和终止日期相差多少天,从而确定slider的最大值
    this.datemax = (endDate - startDate) / (1 * 24 * 60 * 60 * 1000)
    this.startdate = this.timepiker[0]
    this.enddate = this.timepiker[1]
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// Slider
formatTooltip(val) {
  // 格式化tooltip,使tooltip显示当前日期,val为当前slider绑定值
  const startdate = Date.parse(this.dateselect[0])
  const nowdate = new Date(startdate + 1 * 24 * 60 * 60 * 1000 * val)
  const Y = nowdate.getFullYear()
  const M =
    nowdate.getMonth() + 1 < 10
      ? '0' + (nowdate.getMonth() + 1)
      : nowdate.getMonth() + 1
  const D = date.getDate() < 10 ? '0' + nowdate.getDate() : nowdate.getDate()
  const nowdate = `${Y}-${M}-${D}`
  //当前日期格式为"yyyy-MM-dd"
  return nowDate
},

changeModel() {
// ToDo:传递this.sliderdate给后端,返回当前日期下,存在的模型的链接以及模型id。
}

效果

选择起始和终止日期后,滑块会显示所有日期,拖动日期滑块即可控制对应模型的显示和隐藏。

效果如下图:

最终功能展示图◎ 最终功能展示图

总结

时间戳是 js 里很基础的概念了,不过我之前的项目经历中少有实际应用场景,所以导致我只知道有时间戳这个概念,却忘记了合理运用。

这充分证明了我的开发经验并不充足,知识常用常新,要对那些不熟却很基础的概念需要做到心中有数,能灵活使用。

另外,月份为跨度的时间轴滑块其实也是有实际应用场景的,我也把它贴在最后,权当一个教训吧。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
pickmonth() {
  if (this.timepiker != '') {
    let month1, month2
    month1 = this.timepiker[0].split('-')
    month2 = this.timepiker[1].split('-')
    month1 = parseInt(month1[0]) * 12 + parseInt(month1[1])
    month2 = parseInt(month2[0]) * 12 + parseInt(month2[1])
    this.levelmax = Math.abs(month2 - month1)
    this.startmonth = this.timepiker[0]
    this.endmonth = this.timepiker[1]
  }
}

formatTooltip(val) {
  if (this.timepiker != '') {
    let date = this.timepiker[1].split('-')
    let year = parseInt(date[0])
    let month = parseInt(date[1])
    if (month - ((this.levelmax - val) % 12) > 0) {
      year = year - Math.floor((this.levelmax - val) / 12)
      month = month - ((this.levelmax - val) % 12)
    } else if (month - ((this.levelmax - val) % 12) < 0) {
      year = year - Math.ceil((this.levelmax - val) / 12)
      month = month + 12 - ((this.levelmax - val) % 12)
    } else if (month - ((this.levelmax - val) % 12) == 0) {
      year = year - Math.ceil((this.levelmax - val) / 12)
      month = 12
    }
    return year + '-' + month
  }
}