手把手教你写一个微信小程序日历组件
今天我們一起寫一個(gè)微信小程序日歷組件
微信小程序日歷組件 github.com/749264345/w…
好,我們先看一下要實(shí)現(xiàn)的模樣,如下圖
由以上截圖我們可以看到1.日歷可以通過按鈕【切換展示效果】改變?nèi)諝v的呈現(xiàn)效果,上圖是平鋪模式,下圖是收起滾動(dòng)模式。 2.通過點(diǎn)擊具體的日期可以在頁面上顯示當(dāng)前選中的具體日期。 3.點(diǎn)擊【今天】快速回到當(dāng)日視圖。 4.點(diǎn)擊【?】和【?】切換月份。 上面的四點(diǎn)也是基本的交互需求,我們馬上開始。 首先,我們先結(jié)構(gòu)后樣式,做出最基本的界面結(jié)構(gòu) 這邊我們把整體結(jié)構(gòu)分成上中下,操作顯示區(qū),星期顯示區(qū),日期顯示區(qū)。
<view class='calendar'><!--顯示當(dāng)前年月日--><view class='calendar-title'><view class='item ctrl' bindtap='lastMonth'>{{lastMonth}}</view><view class='item title'>{{title}}</view><view class='item ctrl' bindtap='nextMonth'>{{nextMonth}}</view><view class='item ctrl today' bindtap='today'>今天</view></view><!--星期--><view class='calendar-week'><view class='item'>{{item}}</view></view><!--日期--><view class='calendar-container'><!--上個(gè)月占位格子--><view class='grid gray'>{{item}}</view><!--當(dāng)月格子--><view class='grid'><view class="wrap">{{item.date}}</view></view><!--下個(gè)月占位格子--><view class='grid gray'>{{item}}</view></view> </view> 復(fù)制代碼這是我們基本的日歷結(jié)構(gòu),機(jī)智的小伙伴已經(jīng)從布局中知道我們實(shí)現(xiàn)的大致邏輯了,是的,我們先獲取當(dāng)月有多少天,上月和下月有多少天,這樣我們的日歷就出來了。好,慢慢來,下面我們?cè)敿?xì)說,我們先寫上基本的樣式。
.calendar {width: 100%;text-align: center;font-size: 30rpx;box-sizing: border-box; }/* 標(biāo)題 */ .calendar-title {line-height: 70rpx;font-size: 30rpx;text-align: left;padding: 0 20rpx;box-sizing: border-box; }.calendar-title .ctrl {display: inline-block;padding: 0 20rpx;background: #f5f5f5;border-radius: 10rpx; }.calendar-title .item {display: inline-block;vertical-align: middle;line-height: 50rpx; }.calendar-title .title {min-width: 300rpx;text-align: center; }.calendar-title .today {float: right;margin-top: 10rpx; }/* 星期 */ .calendar-week {display: flex;text-align: center;padding: 20rpx 10rpx;box-sizing: border-box;border-top: 1rpx solid #e0e0e0;border-bottom: 1rpx solid #e0e0e0;background: #f5f5f5; }.calendar-week .item {flex: 1; }/* 日期 */ .calendar-container {display: flex;flex-wrap: wrap;padding: 20rpx 10rpx;box-sizing: border-box; }.calendar-container .grid {display: inline-block;width: 14.28571428571429%;line-height: 70rpx;position: relative;z-index: 1; }.calendar-container .grid.gray {color: #ccc; }.calendar-container .grid .wrap.select {background: rgb(49, 120, 228);border-radius: 10rpx;color: #fff;width: 80%;margin: 0 auto; } 復(fù)制代碼以上我們基本試下了日歷的界面,下面我們來實(shí)現(xiàn)星期和日期的展示。 好,我們先顯示星期,我們先在組件中定義一個(gè)數(shù)組,用來遍歷顯示星期的標(biāo)題;
Component({properties: {//星期數(shù)組weekText: {type: Array,value: ['周日', '周一', '周二', '周三', '周四', '周五', '周六']}},... }) 復(fù)制代碼我們將星期的標(biāo)題定義為可配置的模式,默認(rèn)顯示如上的文字,之后我們可以在組件外自定義,個(gè)性化顯示。于是我們調(diào)整下wxml的代碼。
<!--遍歷星期--><view class='calendar-week'><view wx:for='{{weekText}}' class='item' wx:key='{{item}}'>{{item}}</view></view> 復(fù)制代碼這樣我們就能看到我們想要的效果。
下面我們開始日期的顯示,我們先獲取當(dāng)月有幾天,這里的核心代碼是new Date(year, month, date).getDate();
由此我們做如下嘗試
我們?nèi)缙讷@得了返回值,而當(dāng)我們傳入日期為0時(shí)返回了31為當(dāng)月的全部天數(shù)。由于JavaScript中day的范圍為1~31中的值,所以當(dāng)設(shè)為0時(shí),會(huì)向前 一天,也即表示上個(gè)月的最后一天,通過這種方式可以得到每個(gè)月份的天數(shù)。
知道了獲取當(dāng)月天數(shù)的原理,我們還需要知道當(dāng)月1號(hào)是星期幾。 我們使用如下的方法:
new Date(Date.UTC(year, month-1, date)).getDay();
我們同樣在控制臺(tái)做出調(diào)試; 需要注意的是,上面的month是實(shí)際的月份,而下面這個(gè)方法需要在實(shí)際的月份上減去1。 于是我們獲取0-6之間的值,分別對(duì)應(yīng)周日~周六。 值為6是周六,值為0是周日。 由于日歷的第一天是周日,周日對(duì)應(yīng)的是0,于是傳入每月1日,返回值為多少,就是星期幾,也就說明當(dāng)月1日前面空幾格。 知道了當(dāng)月就幾天,當(dāng)月前面有幾天,我們做一下算法就可以得出,當(dāng)月后面有幾天,于是我們建立如下函數(shù): // 組件的初始數(shù)據(jù)data: {//當(dāng)月格子thisMonthDays: [],//上月格子empytGridsBefore: [],//下月格子empytGridsAfter: [], },methods: {//獲取當(dāng)月天數(shù)getThisMonthDays: function (year, month) {return new Date(year, month, 0).getDate();},// 繪制當(dāng)月天數(shù)占的格子createDays: function (year, month) {let thisMonthDays = [],days = this.getThisMonthDays(year, month);for (let i = 1; i <= days; i++) {thisMonthDays.push({date: i,dateFormat: this.zero(i),monthFormat: this.zero(month),week: this.data.weekText[new Date(Date.UTC(year, month - 1, i)).getDay()]});}this.setData({thisMonthDays})},//獲取當(dāng)月空出的天數(shù)createEmptyGrids: function (year, month) {let week = new Date(Date.UTC(year, month - 1, 1)).getDay(),empytGridsBefore = [],empytGridsAfter = [],emptyDays = (week == 0 ? 7 : week);//當(dāng)月天數(shù)var thisMonthDays = this.getThisMonthDays(year, month);//上月天數(shù)var preMonthDays = month - 1 < 0 ? this.getThisMonthDays(year - 1, 12) : this.getThisMonthDays(year, month - 1);//空出日期for (let i = 1; i <= emptyDays; i++) {empytGridsBefore.push(preMonthDays - (emptyDays - i));}var after = (42 - thisMonthDays - emptyDays) - 7 >= 0 ? (42 - thisMonthDays - emptyDays) - 7 : (42 - thisMonthDays - emptyDays);for (let i = 1; i <= after; i++) {empytGridsAfter.push(i);}this.setData({empytGridsAfter,empytGridsBefore})},//補(bǔ)全0zero: function (i) {return i >= 10 ? i : '0' + i;}, } 復(fù)制代碼我們同樣修改下wxml代碼,同時(shí)我們?yōu)樯显?#xff0c;下月,今天,三個(gè)按鈕添加相關(guān)事件監(jiān)聽。
<!--顯示當(dāng)前年月日--><view class='calendar-title'><view class='item ctrl' bindtap='lastMonth'>{{lastMonth}}</view><view class='item title'>{{title}}</view><view class='item ctrl' bindtap='nextMonth'>{{nextMonth}}</view><view class='item ctrl today' bindtap='today'>今天</view></view> 復(fù)制代碼<!--上個(gè)月占位格子--> <view class='grid gray' wx:for='{{empytGridsBefore}}' wx:key='{{item}}'>{{item}}</view><!--當(dāng)月格子--> <view class='grid' wx:for='{{thisMonthDays}}' wx:key='{{indx}}'><view class='self' wx:if="{{ format === year+'-'+item.monthFormat+'-'+item.dateFormat }}"></view><view class="wrap {{ select === year+'-'+item.monthFormat+'-'+item.dateFormat ? 'select' :''}}" bindtap='select' data-date='{{item.date}}'>{{item.date}}</view> </view><!--下個(gè)月占位格子--> <view class='grid gray' wx:for='{{empytGridsAfter}}' wx:key='{{item}}'>{{item}}</view> 復(fù)制代碼相關(guān)的事件監(jiān)聽:
//默認(rèn)選中當(dāng)天 并初始化組件 today: function () {let DATE = this.data.defaultValue ? new Date(this.data.defaultValue) : new Date(),year = DATE.getFullYear(),month = DATE.getMonth() + 1,date = DATE.getDate(),select = year + '-' + this.zero(month) + '-' + this.zero(date);this.setData({format: select,select: select,year: year,month: month,date: date,YEAR: year,MONTH: month,DATE: date,})//初始化日歷組件UIthis.display(year, month, date);//發(fā)送事件監(jiān)聽this.triggerEvent('select', select); }, //上個(gè)月 lastMonth: function () {let month = this.data.month == 1 ? 12 : this.data.month - 1;let year = this.data.month == 1 ? this.data.year - 1 : this.data.year;//初始化日歷組件UIthis.display(year, month, 0); }, //下個(gè)月 nextMonth: function () {let month = this.data.month == 12 ? 1 : this.data.month + 1;let year = this.data.month == 12 ? this.data.year + 1 : this.data.year;//初始化日歷組件UIthis.display(year, month, 0); }, 復(fù)制代碼代碼中我們使用this.display(year, month, 0)為組件統(tǒng)一初始化; 同時(shí)在today函數(shù)中我們添加事件監(jiān)聽函數(shù),將選中的日期發(fā)送到頁面,我們通過事件訂閱來獲取的相關(guān)值。
<Calendar id="Calendar" bind:select="select"></Calendar> 復(fù)制代碼//組件監(jiān)聽事件 select(e) {this.setData({selectVal:e.detail}) }, 復(fù)制代碼最后我們?yōu)榍袚Q顯示效果的按鈕添加事件:
toggleType(){this.selectComponent('#Calendar').toggleType();} 復(fù)制代碼組件中對(duì)應(yīng)的方法,每當(dāng)切換展示效果,組件都需要初始化
//切換展示toggleType(){this.setData({toggleType: this.data.toggleType == 'mini' ? 'large' :'mini'})//初始化日歷組件UIthis.display(this.data.year, this.data.month, this.data.date);}, 復(fù)制代碼以上基本上是小程序日歷組件實(shí)現(xiàn)的基本邏輯,介于篇幅太長還有很多實(shí)現(xiàn)上的細(xì)節(jié)不在此一一細(xì)說,大家可以移步我的github
微信小程序日歷組件 github.com/749264345/w…
上文中有不足之處,請(qǐng)給出建議或更優(yōu)的實(shí)現(xiàn)方案,謝謝~ 最后祝大家五一快樂~~
轉(zhuǎn)載于:https://juejin.im/post/5cca677b51882544dc0f5b56
總結(jié)
以上是生活随笔為你收集整理的手把手教你写一个微信小程序日历组件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 12.09个人博客
- 下一篇: 简 易 版 线 程 池 模