calendar.wxml
<view class="flex box box-tb box-align-center"> <view class="calendar pink-color box box-tb"> <view class="top-handle fs28 box box-lr box-align-center box-pack-center"> <view bindtap="chooseYearAndMonth" class="date-area">{{curYear || initYear}}年{{curMonth || initMonth}}月<view class="sjx"></view> </view> <view class="next-handle" bindtap="nowToday" data-handle="next"> <view>今天</view> </view> </view> <view class="weeks box box-lr box-pack-center box-align-center"> <view class="flex week fs28" wx:for="{{weeksCh}}" wx:key="{{index}}" data-idx="{{index}}">{{item}}</view> </view> <view class="days box box-lr box-wrap" bindtouchstart="touchstart" bindtouchmove="touchmove" bindtouchend="touchend"> <view wx:if="{{hasEmptyGrid}}" class="grid white-color box box-align-center box-pack-center" wx:for="{{empytGrids}}" wx:key="{{index}}" data-idx="{{index}}"> </view> <view class="grid white-color box box-align-center box-pack-center" wx:for="{{days}}" wx:key="{{index}}" data-idx="{{index}}" catchtap="tapDayItem"> <view style="display:flex;flex-direction:column;" class="day box box-align-center box-pack-center"> <text class="border-radius {{item.day == dateItem ? (dateItem==initDate&&initYear==curYear&&curMonth==initMonth) ? ‘pink-bg‘ : ‘pink-bg1‘ : ‘‘}}">{{item.day}}</text> </view> </view> </view> </view> <view class="date-cur"> <view class="border-date"></view> <view class="month-date">{{curMonth || initMonth}}月{{dateItem}}日</view> <view class="border-date"></view> </view> <view class="list-box" wx:if="{{nodeList.length}}"> <view wx:for="{{nodeList}}"> </view> </view> <view class="no-data" wx:elif="{{!nodeList.length}}">暂无数据</view> </view> <view class="{{showPicker ? ‘f-layer‘ : ‘‘}}"> <view class="box box-tb s-picker {{showPicker ? ‘showPicker‘ : ‘‘}}"> <view class="picker-btns box box-lr box-pack-between box-align-center"> <view class="picker-btn picker-cancel" data-type="cancel" bindtap="tapPickerBtn">取消</view> <view class="picker-btn picker-confirm" data-type="confirm" bindtap="tapPickerBtn">确定</view> </view> <picker-view class="flex" indicator-style="height: 50px;" style="width: 100%; height: 150px;" value="{{pickerValue}}" bindchange="pickerChange"> <picker-view-column> <view class="picker-view" wx:for="{{pickerYear}}" wx:key="*this" style="line-height: 50px">{{item}}年</view> </picker-view-column> <picker-view-column> <view class="picker-view" wx:for="{{pickerMonth}}" wx:key="*this" style="line-height: 50px">{{item}}月</view> </picker-view-column> </picker-view> </view> </view>
calendar.js
let chooseYear = null; let chooseMonth = null; let aboutSlide = null; const conf = { data: { hasEmptyGrid: false, showPicker: false, dateItem: new Date().getDate(), initDate: new Date().getDate(), initYear: new Date().getFullYear(), initMonth: new Date().getMonth() + 1 }, // 左右滑动start touchstart(e) { const t = e.touches[ 0 ]; const startX = t.clientX; const startY = t.clientY; this.setData({ initstartX: startX, initstartY: startY }); // console.log(this.data.initstartX,this.data.initstartY,‘chushi‘) }, touchmove(e) { const t = e.touches[ 0 ]; const startX = t.clientX; const startY = t.clientY; this.setData({ movestartX: startX, movestartY: startY }); }, touchend(e) { if(!this.data.movestartX){ return } let distanceX = Math.abs(this.data.movestartX - this.data.initstartX) let distanceY = Math.abs(this.data.movestartY - this.data.initstartY) if(distanceX < 100 || distanceY > distanceX){ this.setData({ movestartX: 0 }); return } let curYear = this.data.curYear; let curMonth = this.data.curMonth - 1 // console.log(this.data.movestartX,this.data.initstartX,123) if(this.data.movestartX-this.data.initstartX > 100){ curYear = this.data.curYear; curMonth = this.data.curMonth - 1 if(curMonth < 1){ curMonth = 12 curYear = curYear - 1 } if(curYear < 2010){ this.setData({ movestartX: 0 }); return } // 正数往右,月份减1 } if(this.data.movestartX-this.data.initstartX < -100){ curYear = this.data.curYear; curMonth = this.data.curMonth + 1 if(curMonth > 12){ curMonth = 1 curYear = curYear + 1 } let maxYear = new Date().getFullYear() + 10; if(curYear > maxYear){ this.setData({ movestartX: 0 }); return } // 负数往左,月份加1 } if (this._calcDaysFn(curYear, curMonth) < this.data.dateItem){ this.setData({ dateItem: this._calcDaysFn(curYear, curMonth) }) } this.calculateEmptyGrids(curYear, curMonth); this.calculateDays(curYear, curMonth); this.setData({ curYear:curYear, curMonth:curMonth }); aboutSlide = null // this._myNodeData(curYear,curMonth) this.setData({ movestartX: 0 }); }, // 左右滑动end onLoad() { aboutSlide = null; const date = new Date(); const curYear = date.getFullYear(); const curMonth = date.getMonth() + 1; const weeksCh = [‘周日‘, ‘周一‘, ‘周二‘, ‘周三‘, ‘周四‘, ‘周五‘, ‘周六‘]; this.calculateEmptyGrids(curYear, curMonth); this.calculateDays(curYear, curMonth); this.setData({ curYear, curMonth, weeksCh }); }, getThisMonthDays(year, month) { return new Date(year, month, 0).getDate(); }, getFirstDayOfWeek(year, month) { return new Date(Date.UTC(year, month - 1, 1)).getDay(); }, calculateEmptyGrids(year, month) { const firstDayOfWeek = this.getFirstDayOfWeek(year, month); let empytGrids = []; if (firstDayOfWeek > 0) { for (let i = 0; i < firstDayOfWeek; i++) { empytGrids.push(i); } this.setData({ hasEmptyGrid: true, empytGrids }); } else { this.setData({ hasEmptyGrid: false, empytGrids: [] }); } }, calculateDays(year, month) { let days = []; const thisMonthDays = this.getThisMonthDays(year, month); for (let i = 1; i <= thisMonthDays; i++) { days.push({ day: i }); } this.setData({ days }); }, nowToday(e) { // console.log(‘今天‘) let that = this; if(this.data.curYear == new Date().getFullYear() && this.data.curMonth == new Date().getMonth() + 1){ this.setData({ dateItem: new Date().getDate() }); return } this.calculateEmptyGrids(new Date().getFullYear(), new Date().getMonth() + 1); this.calculateDays(new Date().getFullYear(), new Date().getMonth() + 1); this.setData({ dateItem: new Date().getDate(), curYear: new Date().getFullYear(), curMonth: new Date().getMonth() + 1 }) aboutSlide = null; // this._myNodeData(new Date().getFullYear(),new Date().getMonth() + 1) }, tapDayItem(e) { let that = this; const idx = e.currentTarget.dataset.idx; const days = this.data.days; this.setData({ days, dateItem: days[idx].day }); // console.log(this.data.nodeList) // console.log(‘点击日历选择第 ‘ + this.data.dateItem+‘ 天‘) }, chooseYearAndMonth() { const curYear = this.data.curYear; const curMonth = this.data.curMonth; let pickerYear = []; let pickerMonth = []; let maxYear = new Date().getFullYear() + 10; for (let i = 2010; i <= maxYear; i++) { pickerYear.push(i); } for (let i = 1; i <= 12; i++) { pickerMonth.push(i); } const idxYear = pickerYear.indexOf(curYear); const idxMonth = pickerMonth.indexOf(curMonth); this.setData({ pickerYear, pickerMonth }) this.setData({ pickerValue: [idxYear, idxMonth], showPicker: true, }); }, pickerChange(e) { const val = e.detail.value; aboutSlide = true chooseYear = this.data.pickerYear[val[0]]; chooseMonth = this.data.pickerMonth[val[1]]; }, tapPickerBtn(e) { const type = e.currentTarget.dataset.type; if(aboutSlide == null){ chooseYear = this.data.curYear || new Date().getFullYear(); chooseMonth = this.data.curMonth || new Date().getMonth() + 1; } const o = { showPicker: false, }; // console.log(‘确定日期前‘,this.data.curYear,this.data.curMonth) let tempYear = this.data.curYear let tempMonth = this.data.curMonth if (type === ‘confirm‘) { o.curYear = chooseYear; o.curMonth = chooseMonth; if (this._calcDaysFn(chooseYear, chooseMonth) < this.data.dateItem){ this.setData({ dateItem: this._calcDaysFn(chooseYear, chooseMonth) }) } this.calculateEmptyGrids(chooseYear, chooseMonth); this.calculateDays(chooseYear, chooseMonth); } // console.log(‘选择确定: ‘ + chooseYear+‘年‘ +chooseMonth+‘月‘+this.data.dateItem+‘日‘) this.setData(o); if(type === ‘cancel‘){ return } // console.log(‘确定日期后,年月相同不调接口‘,this.data.curYear,this.data.curMonth) if(this.data.curYear == tempYear && this.data.curMonth == tempMonth){ return } // this._myNodeData(chooseYear,chooseMonth) }, _calcDaysFn(year, month) { // 计算每个月的最大天数 if (month == 2) { if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0 && year % 4000 != 0)) { return 29; } else { return 28; } } else { if (month == 4 || month == 6 || month == 9 || month == 11) { return 30; } else { return 31; } } } }; Page(conf);
calendar.wxss
page { display: flex; flex-direction: column; width: 100%; background-color: #f3f6fb; } .box { display: flex; } .box-lr { flex-direction: row; } .f-layer{ width:100%; height:100%; position: fixed; background: rgba(0, 0, 0, 0.6); } .box-tb { flex-direction: column; } .s-picker{ position: fixed; bottom:0; left: 0; width:100%; background:#fff; transition: all .3s; transform: translate(0,100%); } .showPicker{ transform: translate(0,0); } .box-pack-center { justify-content: center; } .box-pack-between { justify-content: space-between; } .box-align-center { align-items: center; } .box-wrap { flex-wrap: wrap; } .flex { flex-grow: 1; } .pink-color { background-color: #fff; color: #666666; } .white-color { color: #fff; } .fs28 { font-size: 28rpx; } .top-handle { width:100%; height: 80rpx; position:relative; line-height: 80rpx; box-sizing: border-box; border-top:1px solid #eaeaea; border-bottom:1px solid #eaeaea; } .next-handle{ position:absolute; text-align: center; width:110rpx; right:0; top:0; } .date-area { height: 80rpx; text-align: center; color: #666666; font-size:28rpx; position: relative; padding-right:28rpx; } .sjx{ position: absolute; right:0; top:37rpx; width: 0; height: 0; border-left: 8rpx solid transparent; border-right: 8rpx solid transparent; border-top: 8rpx solid #666666; } .weeks { width:100%; height: 50rpx; line-height: 50rpx; box-sizing: border-box; padding-top:60rpx; padding-bottom:30rpx; color: #0073ff; font-size: 28rpx; } .week { text-align: center; } .days { min-height: 500rpx; width:750rpx; } .grid { width: 107.1428571429rpx; } .day { width: 60rpx; min-height: 60rpx; color: #666666; font-size: 28rpx; } .border-radius{ height:60rpx; width:60rpx; text-align: center; line-height: 60rpx; border-radius: 50%; position: relative; left: 0; top: 0; } .pink-bg { color: #fff; background-color: #3880f4; } .pink-bg1{ color: #fff; background-color: #bec1c5; } .date-status{ display: flex; flex-wrap:wrap; width:34rpx; height:40rpx; justify-content: center; margin-left:6rpx; } .date-status .wai{ width:50%; height:20rpx; } .date-status .wai view{ height:12rpx; width:12rpx; border-radius: 50%; } .date-status .rg{ margin-bottom: 18rpx; } .spot-com{ background-color: #73bc23; } .spot-yq{ background-color: #ff4d4d; } .spot-wdq{ background-color: #5c9aff; } .spot-com-yq{ background-color: #ff9b1a; } .purple-bg { background-color: #b8b8f1; } .date-cur{ width:100%; height:80rpx; box-sizing: border-box; padding:0 53rpx; display: flex; align-items: center; font-size: 24rpx; } .border-date{ height:1px; width:210rpx; background-color: #eaeaea; } .month-date{ width:224rpx; text-align: center; color: #999999; } .list-box{ padding:0 30rpx; box-sizing: border-box; } .picker-btns { height: 120rpx; line-height: 120rpx; border-bottom: 1rpx solid #eee; } .picker-confirm { margin-right: 50rpx; } .picker-cancel { margin-left: 50rpx; } .picker-view { color: #666666; text-align: center; } .no-data{ margin-top:100rpx; color: #999999; }