前言
前些时间导师接了一个数字孪生的小项目,让我一个人完成前端三维隧道看板以及填报系统的构建。
技术路线:vue element admin + element ui + arcgis api for javascript。
最近项目接近尾声,我记录一下之前遇到一下项目过程中犯得一个幼稚的错误。
需求
前端实现一个日期滑块,要能选择开始和结束日期,通过滑动日期滑块选择某日期前所有模型的显隐,达到模拟施工进度的效果。
ps:模型属性没日期,需要将日期传给后端,然后后端返回模型的链接以及模型 id。
思路
说多了,继续回到标题。制作一个日期滑块,自然而然地想到了利用 elemnet ui 的datepiker组件和slider组件。Datepiker 负责选择起始日期,然后将选择的日期传给 slider,然后调用 slider 组件的 input 方法,将日期轴上变化的时间传给后端。So easy,看来今天能早点下班。


结果等我想传值的时候,突然发现 slider 的绑定值是 number 类型,但是一年 365 天的日期不连续,甚至偶尔还有 366 天出来捣乱,我该怎么将日期跟 number 关联上?最开始的想法是计算起始日期给和 slider 绑定的 value 计算硬算出当前日期,后来考虑到大小月平闰年的,属实不现实,我直呼做不了。
但是甲方直呼 arcgis api 有现成的sample啊,他们是怎么做到?我看了看确实有时间轴,也确实能过滤要素。但是他的日期是固定的啊,固定的时间轴谁不会啊?甲方表示不听不听,王八念经。
不过能力不够,我很抱歉,只能先做一个可以自由选择起始和终止月份的时间轴先应付着,把别的简单功能先完成,再回头做这个吧。甲方无奈之下,也只能暂时妥协。
按月份做时间轴滑块的思维过程就很流畅了,先计算起始月份和终止月份相差多少个月确定 slider 的最大值,然后根据 slider 的绑定值加上起始月份除以 12 求商并取余就能得到当前绑定值是哪年哪月了。
后来其他需求做的差不多,甲方表示时间轴的精度太低了,这样哪还有施工进度模拟的感觉,一个月有将近三十天,那就每个月取三个日期,1 号,11 号,21 号吧,效果看起来能好点。
啧,感觉他们的需求很合理啊,这么正常的需求我做不出来,肯定是我能力不够,就想去我去网上看看有没有现成的轮子。结果我检索能力也不行,找了一圈没找到合适的。
算了,我自己再想想,顺便去做了个核酸,喉咙被戳得挺不爽的,突然一时就思路清晰了,用时间戳啊,时间戳每天的时长固定的而且能跟日期相互转换。起始日期转为时间戳,然后加上 slider 绑定值的天数的时长,再转换为当前日期就完成了。这么简单的事,我一时居然想不到,果然是我还是经验不够能力不行。
代码
// 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]
}
}
// 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 里很基础的概念了,不过我之前的项目经历中少有实际应用场景,所以导致我只知道有时间戳这个概念,却忘记了合理运用。
这充分证明了我的开发经验并不充足,知识常用常新,要对那些不熟却很基础的概念需要做到心中有数,能灵活使用。
另外,月份为跨度的时间轴滑块其实也是有实际应用场景的,我也把它贴在最后,权当一个教训吧。
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
}
}