• 小程序-从零实现日历查看器


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

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

    先具体说一下思路吧:

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

    空字符对应的就是红色框框中的内容,图片日历表中的数组是这样子的:["","",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);
      },

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

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

  • 相关阅读:
    Uber Go 语言编码规范
    前端架构演进
    看完微软大神写的求平均值代码,我意识到自己还是too young了 https://mp.weixin.qq.com/s/r2nOJvviqK2bZAumNkc7g
    React v18.0 How to Upgrade to React 18
    重写历史 Rewriting History
    记一次网页内存溢出分析及解决实践
    降低了IP层的效率 根据对方给出的窗口值和当前网络的拥塞的程度决定一个报文段应包含多少个字节
    京东家庭号前端分层架构演进及赋能实践
    深入了解 Go 语言与并发编程 GMP
    BBR原理导读
  • 原文地址:https://www.cnblogs.com/liao123/p/12810842.html
Copyright © 2020-2023  润新知