小程序开发日志-2、从零实现日历选择器

先看一下效果吧,毕竟不知道我写的标题表达得够不够明确。

有没有被帅到?标题说的日历查看器就是这个,那么下面我们来聊聊究竟该怎么实现这个强大好看(有点自恋)的日历查看(选择器)吧。

先具体说一下思路吧:

这个日历查看器其实最大的难点是怎么把月份和周的数据给对应上,其实利用数组很好解决这个问题,我们可以将月份的数据存入到数组中,日历表渲染就把这个数组遍历一下就好了。但在存入的时候,做一下小小的判断去给里面加几个空字符。那这个空字符是干嘛的呢?看下面一张图:

 

空字符对应的就是红色框框中的内容,图片日历表中的数组是这样子的:["","",1,2,3,......];一直到30号,30号后面就不必再加了。

上面就是基本的一个思路,下面看看应该怎么去做吧!

 

 第一步,我们先创建一个静态的数据渲染先:

我把这个日历选择器分为两个部分,一个部分是操作那个部分,也就是有前进后退按钮那一个版块,另一个部分就是日历表,显示数据的部分。

先把第一部分实现,代码如下:

 <!--日历控制器start-->
    <view class="hours-calendar flex-content border-top p-18">
        <view class="flex-content remote-ctr">
            <image src="/images/agent/pre-icon.png" bindtap="preYearFn"></image>
            <view class="margin-42 color-gray">{{years}}</view>
            <image src="/images/agent/next-icon.png" bindtap="nextYearFn"></image>
        </view>
        <view class="flex-content remote-ctr ml-27">
            <image src="/images/agent/pre-icon.png" bindtap="preMonthFn"></image>
            <view class="margin-42 color-gray">{{months}}月</view>
            <image src="/images/agent/next-icon.png" bindtap="nextMonthFn"></image>
        </view>
        <view class="ml-auto back-btn" bindtap="backToFn">
            回到今天
        </view>
    </view>
    <!--日历控制器end-->

上面是.wxml文件的部分,那些图片其实是左右箭头类的,最后会给大家贴一下,有需要的朋友可以自行下载喔!

接下来看看样式代码:

.hours-calendar{
    padding: 35rpx 48rpx;
    background-color: #ffffff;
}
.remote-ctr image{
    width: 19rpx;
    height: 35rpx;
}
.margin-42{
    margin: 0 42rpx;
}
.ml-27{
    margin-left: 27rpx;
}
.back-btn{
    color: #ec6941;
    border-radius: 10rpx;
    border: 2rpx solid #ec6941;
    padding: 6rpx 21rpx;
}
.calendar-content{
    padding-bottom: 30rpx;
    background-color: #ffffff;
}

全局中公用的样式:

.flex-content{
  display: flex;
  align-items: center;
}
.border-top{
  border-top: 2rpx solid #e8e8e8;
}
.color-gray{
  color: #a0a0a0;
}
.ml-auto{
  margin-left: auto;
}

实现第二部分日历表,同样利用强大的flex布局,然后让它去自动换行就ok了

<view class="calendar-content p-18 color-gray border-top">
        <view class="flex-content week">
            <view></view>
            <view></view>
            <view></view>
            <view></view>
            <view></view>
            <view></view>
            <view></view>
        </view>
        <view class="flex-wrap week">
            <view data-day="{{item}}" wx:for="{{30}}" wx:key="key">{{item}}</view>
        </view>
    </view>

加上样式:

.calendar-content{
    padding-bottom: 30rpx;
    background-color: #ffffff;
}
.week view{
    width: 64rpx;
    height: 64rpx;
    text-align: center;
    line-height: 64rpx;
    margin-left: 38rpx;
    margin-top: 10rpx;
}
.is-today{
    border-radius: 50%;
    background-color: #dfdfdf;
    position: relative;
}
.is-today::after{
    content: "今天";
    position: absolute;
    bottom: -20rpx;
    left: -3rpx;
    font-size: 12rpx;
    width: 70rpx;
}
.se-day{
    border-radius: 50%;
    background-color: #ec6941;
    color: #ffffff;
}

这样一个静态的日历表就出来了,效果如下:

 

有个0?这是数组遍历的惯性,大家知道就好了。

那么接下来就是我们的重点了,究竟怎么让周和月份对应上?

先创建一个日历js方法文件,calendar.js

然后贴出代码:

/**
 * 返回月份数组
 * @param year
 * @param month
 * @returns {*[]}
 */
const getMonthList = function (year, month) {
    let date = new Date();
    if(year){
        date.setFullYear(year);
        date.setMonth(month - 1);
        date.setDate(1);
        let weekIndex = (date.getDay() - 1) < 0 ? 6 : (date.getDay() - 1);
        //获取本月总天数方法---将当前月份加1,下移到下一个月
        console.log(month + ',设置的月份为:' + date.getMonth());
        console.log('设置的礼拜为:' + weekIndex);
        date.setMonth(date.getMonth() + 1);
        //将当前日期置为0
        date.setDate(0);
        console.log('获取的天数为:' + date.getDate());
        //再获取天数即取上一个月的最后天数
        let days = date.getDate();
        let monthList =[];
        //周几开始加上总天数,就是所生产数组的总个数
        for(let i = 0; i < (weekIndex + days); i++){
            if(weekIndex > i){
                monthList.push('');
            }else if((i) < (days + weekIndex + 1)){
                monthList.push((i + 1) - weekIndex);
            }else {
                monthList.push('');
            }
        }
        return monthList;
    }
}
module.exports = {
    getMonthList: getMonthList,
}

上述的思路就跟开篇上将的是一样的,可以对照上面一起看。

有了这个方法之后,它可以根据我们传递的年份和月份,把一个带有空字符处理好的数组返回给我们。

然后我们稍稍修改一下原来那个遍历的wx:for那里的代码:

<view class="{{item === isToday ? 'is-today' : ''}} {{item === selectDay ? 'se-day' : ''}}" data-day="{{item}}" wx:for="{{calendarList}}" wx:key="key" bindtap="selectDayFn">{{item}}</view>

在生命周期函数加载的时候,自动获取本月的日历表:

/**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    this.setData({
      groupId: Number(options.groupId),
    });
    wx.setNavigationBarTitle({
      title: options.name + '-工时'
    });
    this.backToFn();
  },

上面用到的backToFn其实就是一个回到今天的函数,不过是跟初始加载是一样的。

/**
   * 初始化当天日期数据
   */
  backToFn(){
    let _date = new Date();
    this.resetDataFn( _date.getFullYear(),_date.getMonth() + 1,_date.getDate());
  },

什么?又包含了一个函数?这个resetDataFn是重点,下面会有四个函数会公用到,编程思想嘛,当然是能拆分就尽量拆分。

/**
   * 数据重置
   * @param years 年份
   * @param months 月份
   * @param days 天
   */
  resetDataFn(years, months, days = this.data.isToday){
    this.setData({
      years:  years,
      months: months,
      isToday: days,
      calendarList: calendar.getMonthList(years,months),
    })
  },

数据忘记初始化了:

下面我们在小程序页面js文件中声明的几个变量:

data: {
    calendarList: [],
    years: 0,
    months: 0,
    isToday: 0,
    selectDay: 0,
  },

calendarList是日历表数组,years是年份,months是月份,isToday是天数,selectDay是被点击的天数(后面会用到)。

等等,似乎还忘记了什么东西?还没实现怎么选择呢?

变量声明好了,再来什么几个函数:Pages({})下。

/**
   * 上一年
   */
  preYearFn(){
    let _date = new Date();
    console.log(`${this.data.months},${_date.getMonth() + 1}`);
    let _days = this.data.years - 1 === _date.getFullYear() && (_date.getMonth() + 1) === this.data.months ? _date.getDate() : 0;
    this.resetDataFn(this.data.years - 1, this.data.months, _days);
  },
  /**
   * 下一年
   */
  nextYearFn(){
    let _date = new Date();
    let _days = this.data.years + 1 === _date.getFullYear() && (_date.getMonth() + 1) === this.data.months ? _date.getDate() : 0;
    this.resetDataFn(this.data.years + 1, this.data.months, _days);
  },
  /**
   * 上一月
   */
  preMonthFn(){
    let _date = new Date();
    let _months = this.data.months - 1 === 0 ? 12 : this.data.months - 1;
    let _years = this.data.months - 1 === 0 ? this.data.years - 1 : this.data.years;
    let _days = (_date.getMonth() + 1) === _months && this.data.years === _date.getFullYear() ? _date.getDate() : 0;
    this.resetDataFn(_years, _months, _days);
  },
  /**
   * 下一个月
   */
  nextMonthFn(){
    let _date = new Date();
    let _months = this.data.months + 1 === 13 ? 1 : this.data.months + 1;
    let _years = this.data.months + 1 === 13 ? this.data.years + 1 : this.data.years;
    let _days = (_date.getMonth() + 1) === _months && this.data.years === _date.getFullYear() ? _date.getDate() : 0;
    this.resetDataFn(_years, _months, _days);
  },

上面就是对应了四个按钮:

 

 

 

就这样,一个强大霸气的日历选择查看器就完成了。

 

posted @ 2020-04-30 19:32  padding2020  阅读(494)  评论(0编辑  收藏  举报
想了解更多的,大家也可以关注我的公众号:padding2020