zoukankan      html  css  js  c++  java
  • 微信小程序:手写日历组件

    一、前言

    最近公司要做一个酒店入住的小程序,不可避免的一定会使用到日历,而小程序没有内置的日历组件。在网上看了一下也没有非常适合需求的日历,于是自己写了一个。

    二、代码

    1. 原理分析

    写一个日历只需要知道两件事情:

    1. 一个月有多少天;
    2. 每个月的第一天是星期几。

    2. 功能分析

    由于是酒店入住的日历,所以需要实现如下功能:

    1. 渲染日历,一般是从本月开始,到半年之后的日历
    2. 过去的日期不可选
    3. 实现点击获取入住日期、退房日期,以及改变相应日期的颜色和整个时间段的颜色

    3. 数据分析

    根据最后的功能实现,我生成的每个月的数据结构如下:

    {
        year: 2018,
        month: 3,
        fullMonth: '03',
        allDays:[
            {
                day: 1,
                fullDay: '01',
                fullDate: '2018-03-01'
            },
            {
                day: 2,
                fullDay: '02',
                fullDate: '2018-03-02'
            },
            //......
            //(后面的数据同上)
        ]
    }

    year就是年份,month是月份,day是日期,fullDate是完整日期。
    fullMonth和fullDay原本是两个不需要的数据,但是在点击日期改变颜色的时候用到了,因为小程序没有提供很好的处理数据的filter。当然这个问题也和我的个人水平有关,如果有哪位大神有更好的方法,请留言告诉我。我非常想去掉这两个数据。

    4.代码分析

    // calendar.js文件
    
    Page({
      data: {
        week_list: ['日','一','二','三','四','五','六'],
        startDate: '',
        endDate: '',
        date_click: 0
      },
      // 获取每月总天数
      getAllDaysOfMonth(year,month) {
        return new Date(year,month,0).getDate();
      },
      // 获取每月第一天是星期几
      getFirstDayOfMonth(year,month) {
        return new Date(year, month - 1, 1).getDay();
      },
      // 计算本月前空了几格
      getEmptyGrids(year,month) {
        // FirstDayOfMonth代表本月的第一天是星期几
        const FirstDayOfMonth = this.getFirstDayOfMonth(year, month);
        let emptyGrids = [];
        
        // 有空格的情况
        if (FirstDayOfMonth > 0) {
          for (let i = 0; i < FirstDayOfMonth; i++) {
            emptyGrids.push({
              'num': '',
              'fullDate': 'x'  //x是我自己定义的一个值,代表没有日期
            });
          }
          // 将空格放入数组
          return emptyGrids;
        }else{
          // 否则返回一个新数组
          return [];
        }
      },
      // 计算本月日历
      getDaysOfThisMonth(year,month) {
        let days = [];
        const AllDaysOfMonth = this.getAllDaysOfMonth(year, month);
    
        let fullMonth = month.toString().length === 1 ? `0${month}`:month;
        for (let i = 0; i < AllDaysOfMonth; i++) {
          let day = i+1,
              fullDay = day;
    
          fullDay = fullDay.toString().length === 1 ? `0${day}` : fullDay;
          days.push({
            day,
            fullDay,
            'fullDate': `${year}-${fullMonth}-${fullDay}`
          });
        }
        // 返回每个月的具体日期
        return days;
      },
      // 循环渲染日历
      // 从本月开始渲染,n代表包括本月开始连续渲染几个月
      fillCalendar(n) {
        let year = this.data.cur_year,
            month = this.data.cur_month,
            fullMonth,
            canlendar_data = [];
    
        // 计算年月以及具体日历
        for (let i = this.data.cur_month; i < this.data.cur_month + n; i++) {
          let EmptyGrids = this.getEmptyGrids(year, month);
          let DaysOfThisMonth = this.getDaysOfThisMonth(year, month);
    
          // 把空格和具体日历合为一个数组
          let allDays = [...EmptyGrids, ...DaysOfThisMonth];
    
          // 对年份和月份的计算做一些判断
          if (month > 12) {
            year++;
            month = 1;
            fullMonth = '01'
            canlendar_data.push({
              year, 
              month, 
              fullMonth,
              allDays });
            month++;
          }else{
            fullMonth = month.toString().length === 1 ? `0${month}` : month;
            canlendar_data.push({ 
              year, 
              month, 
              fullMonth,
              allDays });
            month++;
            
          }
    
        }
    
        this.setData({
          canlendar_data
        })
      },
      onLoad() {
        const date = new Date();
        const cur_year = date.getFullYear();
        const cur_month = date.getMonth() + 1;
        const cur_day = date.getDate();
        this.setData({
          date,
          cur_year,
          cur_month,
          cur_day
        })
    
        let month = this.data.cur_month.toString().length === 1 ? `0${this.data.cur_month}` : this.data.cur_month;
        let day = this.data.cur_day.toString().length === 1 ? `0${this.data.cur_day}` : this.data.cur_day;
        let nowDate = `${cur_year}-${month}-${day}`;
    
        this.setData({
          nowDate
        })
    
        this.fillCalendar(6);
      },
      // 点击日期
      chooseDate(e) {
        const year_click = e.currentTarget.dataset.year;
        const month_click = e.currentTarget.dataset.month;
        const day_click = e.currentTarget.dataset.day;
        console.log(year_click,month_click,day_click);
        // 如果是空格或者以前的日期就直接返回
        if(day_click === ''||`${year_click}-${month_click}-${day_click}` < this.data.nowDate) {
          return;
        }
    
        // 获取点击对象的id
        let id = e.currentTarget.dataset.id;
        
        // data_click为0代表选择的是入住日期,否则就是离店日期
        if (this.data.date_click == 0){
          // 选择入住日期
          this.setData({
            startDate: `${year_click}-${month_click}-${day_click}`,
            date_click: 1
          })
        }else {
          let newDay = new Date(Date.parse(id));
          let oldDay = new Date(Date.parse(this.data.startDate));
    
          // 判断第二次点击的日期在第一次点击的日期前面还是后面
          if (newDay > oldDay) {
            this.setData({
              endDate: `${year_click}-${month_click}-${day_click}`,
              date_click: 2
            })
          }else{
            this.setData({
              startDate: `${year_click}-${month_click}-${day_click}`,
              endDate: '',
              date_click: 1
            })
          }
        }
      }
    })
    <!-- calendar.wxml文件 -->
    
    <view class="container">
      <view id="week">
        <view class="week-item {{idx===0||idx===6?'relax':''}}" wx:for="{{week_list}}" wx:for-index="idx">{{item}}</view>
      </view>
      <scroll-view scoll-y="true">
        <view class="month-block" wx:for="{{canlendar_data}}" wx:for-item="canlendar_item">
          <view class="month-title">{{canlendar_item.year}}年{{canlendar_item.month}}月</view>
          <view class="month-content">
            <view class="month-day {{item.fullDate<nowDate?'gray':''}} {{startDate===item.fullDate?'startActive':''}} {{endDate===item.fullDate?'endActive':''}} {{item.fullDate>startDate&&item.fullDate<endDate&&startDate!==''&&endDate!==''?'midActive':''}}" bindtap="chooseDate" data-year="{{canlendar_item.year}}" data-month="{{canlendar_item.fullMonth}}" data-day="{{item.fullDay}}" data-id="{{item.fullDate}}" wx:for="{{canlendar_item.allDays}}">{{item.day}}</view>
          </view>
        </view>
      </scroll-view>
    </view>

    {{idx===0||idx===6?'relax':''}} 是改变周六周日的颜色,
    {{item.fullDate<nowDate?'gray':''}} 是改变过去日期的颜色,
    {{startDate===item.fullDate?'startActive':''}} 判断点击的是入住日期,
    {{endDate===item.fullDate?'endActive':''}} 判断点击的是离店日期,
    {{item.fullDate>startDate&&item.fullDate<endDate&&startDate!==''&&endDate!==''?'midActive':''}} 改变入住日期和离店日期之间的日期颜色

    四、结语

    到此一个简单的日历就完成了,当然这个日历无法满足所有业务需求,但是基本的日历渲染功能以及点击选择功能都有。所以在业务需求之上对其进行小部分改变就可以了,希望大家可以留言指出我的问题,我也会进一步的改善这个日历代码。

  • 相关阅读:
    svn问题(队列)
    linux的七大运行级别及级别修改
    Elasticsearch配置文件说明
    openstack-swift云存储部署(二)
    openstack-swift云存储部署(一)
    今天发现一些很有意思的ubuntu命令
    python使用xlrd 操作Excel读写
    Python初记
    SQL Server常用命令
    SQL Server 流程控制
  • 原文地址:https://www.cnblogs.com/10manongit/p/12722340.html
Copyright © 2011-2022 走看看