基於moment寫一個滑動日曆
阿新 • • 發佈:2018-12-09
效果如圖(日期可左右滑動)
思路:1、先得到相鄰三個周的資料,初始化的時候講容器向左移動一個視口的距離,確保中間周在可視範圍(在可是範圍的所用為1)2、觸控移動階段,比如向左移動,相當於改變可是範圍的索引,也就是2,即向左移動過兩個視口的範圍3、移動結束,這時右邊已經沒有待顯示的資料,需要重組資料,再向後加一週,使當前顯示的周在中間,同時需要改變顯示的索引為1
1、用moment處理日期資料
在當前視口內顯示本週的7天,由於需要滑動,所以事先還需要把今天以前的一週和以後的一週準備好
let today = moment().format('YYYY-MM-DD') // 當前日期:"2018-09-14" moment(today).subtract(7, 'd').format('YYYY-MM-DD') // 上一週的今天:"2018-09-07" moment(today).add(7, 'd').format('YYYY-MM-DD') // 下一週的今天:"2018-09-21"
得到陣列: dates
由此資料可以生成三個模板,分別表示上週,本週和下週,再根據此資料,計算上週,本週和下週的詳情。
getDays: function (day) { let arr = [] /* 計算傳進來的日期為星期幾 */ let weekOfDate = Number(moment(day).format('E')) // 提前定義好的: this.week = ['一', '二', '三', '四', '五', '六', '日'] for (let i = 0; i < this.week.length; i++) { arr.push( { date: moment(day).subtract(weekOfDate - i - 1, 'd').format('YYYY-MM-DD'), week: this.week[i] } ) } return arr }
遍歷陣列dates。分別傳進getDays可的到三週的詳情
然後遍歷陣列進行頁面渲染
<template v-for="(item, index) in dates"> <div class="slider"> <div class="day" v-for="(day, dayIndex) in getDays(item.date)"> <div :class="{today: day.date === defaultDate}">{{day.date.split('-')[2]}}</div> </div> </div> </template>
這裡,靜態顯示已經完成
為元件新增滑動功能
改寫上方的頁面渲染程式碼
<div class="week-slider">
<div
class="sliders"
ref="sliders"
@touchstart="touchStart"
@touchmove="touchmove"
// 初始樣式,應該向飾釦左方移動一個視口的距離,確保當前周在中間
:style="getTransform"
@touchend="touchend"
@webkit-transition-end="transitionEnd"
@transitionend="transitionEnd">
<template v-for="(item, index) in dates">
<div class="slider">
<div class="day" v-for="(day, dayIndex) in getDays(item.date)">
<div :class="{today: day.date === defaultDate}">{{day.date.split('-')[2]}}</div>
</div>
</div>
</template>
</div>
</div>
// actIndex: 當前活動檢視的縮影,初始為1,sliderWidth:視口的寬度, distan: {x:0, y: 0}: 觸控移動的距離
//
getTransform: function () {
this.endx = (-this.actIndex * this.sliderWidth) + this.distan.x
let style = {}
style['transform'] = 'translateX(' + this.endx + 'px)'
// 這一條必須寫,因為觸控移動的時候需要過渡動畫,但是在動畫結束重組資料的時候需要瞬間回到該去的位置,不能要過渡動畫
style['transition'] = this.isAnimation ? 'transform .5s ease-out' : 'none'
return style
}
最後觸控時間處理:
touchStart: function (e) {
this.start.x = e.touches[0].pageX
},
touchmove: function (e) {
// 這裡需要過渡動畫
this.isAnimation = true
this.distan.x = e.touches[0].pageX - this.start.x
// 需要移動的容器
let dom = this.$refs.sliders
// 向左
this.endx = this.endx + this.distan.x
dom.style['transform'] = 'translateX('+ this.endx + 'px)'
},
touchend: function (e) {
this.isAnimation = true
this.distan.x = e.changedTouches[0].pageX - this.start.x
// 向右
if (this.distan.x > 0) {
this.direction = 'right'
this.actIndex = 0
} else if (this.distan.x < 0) {
this.direction = 'left'
this.actIndex = 2
}
this.distan.x = 0
},
過渡結束後重置容器位置
// 過渡結束
transitionEnd: function () {
this.isAnimation = false
if (this.actIndex === 2) {
this.dates.push({
date: moment(this.dates[this.actIndex].date).add(7, 'd').format('YYYY-MM-DD')
})
this.dates.shift()
this.actIndex = 1
}else if (this.actIndex === 0) {
this.dates.unshift({
date: moment(this.dates[this.actIndex].date).subtract(7, 'd').format('YYYY-MM-DD')
})
this.dates.pop()
this.actIndex = 1
}
}