Bootstrap

微信小程序中使用vant中的Calendar 日历组件

需求
  小程序需要实现日历的需求,可以单选、可以选择区间、节假日和周六颜色高亮、返回本月。具体如图,类似猫眼app的日历选择。

在这里插入图片描述

思路:

  1. 参考市场上含有日历的小程序及app,确定是自己实现还是使用组件,骨朵使用的是Pikaday
  2. 确定使用Vant Weapp组件库中日历。
  3. 需要对源码进行一些修改,首先样式的修改、包括顶部周日到周六、节假日及周六日日期的颜色、返回本月按钮的添加及样式。
  4. 前后实现了三种展示日历的不同方式
    4-1. 第一种,根据官方示例引入日历组件,平铺整个页面。选择日期后会跳转返回列表页。
    存在的问题:由于给日历的范围比较大,需要展示三年多的日期,导致渲染的时候比较慢,点进日历页后,页面会白屏1-2秒,整个日历才会显示出来。
    4-2. 第二种,将引入日历的组件文件再作为组件,引入到列表页中,为了解决日历元素渲染久的问题,当日历页作为组件引入到列表页后,让它在列表页提前加载渲染,此时当点击选择日期的时候,日历已经渲染好了。
    存在的问题:由于日历在列表页作为子组件,导致进来后一起渲染,列表页会白屏1-2秒,用户感受不好。决定给引入的日历组件加个变量控制其显示隐藏,给它个定时器,让其延迟加载,设置的时间短了,会中断echarts的渲染过程,echarts会等日历渲染完后,再继续渲染自己的图;设置的时间长了,进来之后点击选择日历没反应,可能还没渲染完。
    4-3. 第三种,通过在列表页让日历以弹框的形式出来,直接将日历组件引入列表页。此时避免了列表页和日历页之间的频繁跳转导致路由堆积过多 。
    存在的问题:虽然通过弹框加载,但日历渲染的时间还是需要1-2秒,如果日历和列表页一起渲染,会导致列表页白屏1-2秒,等到日历渲染完才会展示内容。如果给日历添加定时器让其延迟加载,等列表页渲染完后再去渲染日历,此时列表和图表正常加载,但由于日历没有加载完,选择日期不可点击,并且其他的按钮也不可点击,点击后会触发也会请求接口,但会等到日历渲染完毕才会将刚刚请求的新数据渲染到页面上。考虑给页面整个一个2秒的loading效果,页面可正常看到,2秒后,再让你其操作。
    4-4. 第四种,日历通过弹框形式展现,在页面加载的时候给日历组件加上一个变量asyncLoad,控制其显示隐藏,写在onReady生命周期中,通过定时器给延迟50s,让变量变成true,此时列表一定渲染完成,echarts图可能渲染一半,不考虑图的渲染体验,等到日历组件渲染完成后继续加载图表。此时再去点击日期选择就可以使用了。以下实现步骤为该种方案
  5. 比较好的实现方式应该对这种需要渲染上千个数据的进行虚拟加载,这样就会避免了加载时间过长导致的种种问题。但由于使用的组件,暂时没有实现。

步骤:

  1. 修改样式及组件的属性配置
    下图是下载好的组件库,删掉了没有用的组件
    在这里插入图片描述
    将日历中的日期进行三种展示,分别是,普通日期、节假日、周六日
    在这里插入图片描述
    在这里插入图片描述
    添加返回本月按钮,以及返回本月对应的方法,在开发者工具上好用,但体验版上不好使
    后续删掉了整个按钮,具体问题没有分析
    在这里插入图片描述
    在这里插入图片描述

  2. 修改样式及组件的属性配置

    <!--pages/boxOfficeModule/boxOfficeList/boxOfficeList.wxml-->
    <view style="{{!showCalendar ? 'badisplay:block' : 'background: #4c4c4c;display:none'}}" >
    	<view>页面内容</view>
    	<view class="dayDate">
          <view class="pickerBox {{asyncShow ? 'open' : 'off'}}" bindtap="goCalendar" data-dateBox="{{dateBox}}" data-platformIdIndex="{{platformIdIndex}}">
            <view class="picker">{{dateName}}</view>
            <image class="drop-down" src="../../../images/drop-down.png"></image>
          </view>
        </view>
    </view>
    
    <view>
      <van-calendar wx:if="{{asyncLoad}}" style="{{showCalendar ? 'display:block' : 'display:none'}}" show-mark="{{ false }}" formatter="{{ formatter }}" default-date="{{ defaultVal }}" min-date="{{ minDate }}" max-date="{{ maxDate }}" show="{{ showCal }}" show-confirm="{{ false }}" bind:close="onClose" bind:confirm="onConfirm" round="false" position="bottom"  />
    </view>
    
    
    
    // pages/boxOfficeModule/boxOfficeList/boxOfficeList.js
    var app = getApp()
    var util = require('../../../utils/util.js')
    import * as echarts from '../../../ec-canvas/echarts';
    Page({
    	data: {
    		date: '',
    	    showCal: false,
    	    minDate: new Date(2019, 0, 1).getTime(),
    	    maxDate: new Date().getTime(),
    	    defaultVal: new Date('2021-04-19').getTime(),
    	    formatter(day) {
    	      // console.log('day', day)
    	      const year = day.date.getFullYear()
    	      const month = day.date.getMonth() + 1
    	      const date = day.date.getDate()
    	      let week = day.date.getDay()
    	      if (week === 0) week = 7
    	      const holiday = [
    	        {
    	          year: 2020,
    	          monthDate: [
    	            {
    	              month: 1,
    	              date: [
    	                { day: 1, text: '元旦', holidayColor: true },
    	                { day: 24, text: '除夕', holidayColor: true },
    	                { day: 25, text: '春节', holidayColor: true },
    	              ]
    	            },
    	            {
    	              month: 2,
    	              date: [
    	                { day: 14, text: '情人节', holidayColor: true },
    	                { day: 8, text: '元宵节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 4,
    	              date: [
    	                { day: 1, text: '愚人节', holidayColor: true },
    	                { day: 4, text: '清明节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 5,
    	              date: [
    	                { day: 1, text: '劳动节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 6,
    	              date: [
    	                { day: 1, text: '儿童节', holidayColor: true },
    	                { day: 25, text: '端午节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 8,
    	              date: [
    	                { day: 25, text: '七夕节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 9,
    	              date: [
    	                { day: 10, text: '教师节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 10,
    	              date: [
    	                { day: 1, text: '国庆节', holidayColor: true },
    	                { day: 1, text: '中秋节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 11,
    	              date: [
    	                { day: 11, text: '光棍节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 12,
    	              date: [
    	                { day: 24, text: '平安夜', holidayColor: true },
    	                { day: 25, text: '圣诞节', holidayColor: true }
    	              ]
    	            },
    	          ]
    	        },
    	        {
    	          year: 2021,
    	          monthDate: [
    	            {
    	              month: 1,
    	              date: [
    	                { day: 1, text: '元旦', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 2,
    	              date: [
    	                { day: 14, text: '情人节', holidayColor: true },
    	                { day: 11, text: '除夕', holidayColor: true },
    	                { day: 12, text: '春节', holidayColor: true },
    	                { day: 26, text: '元宵节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 4,
    	              date: [
    	                { day: 1, text: '愚人节', holidayColor: true },
    	                { day: 4, text: '清明节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 5,
    	              date: [
    	                { day: 1, text: '劳动节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 6,
    	              date: [
    	                { day: 1, text: '儿童节', holidayColor: true },
    	                { day: 14, text: '端午节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 8,
    	              date: [
    	                { day: 14, text: '七夕节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 9,
    	              date: [
    	                { day: 10, text: '教师节', holidayColor: true },
    	                { day: 21, text: '中秋节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 10,
    	              date: [
    	                { day: 1, text: '国庆节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 11,
    	              date: [
    	                { day: 11, text: '光棍节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 12,
    	              date: [
    	                { day: 24, text: '平安夜', holidayColor: true },
    	                { day: 25, text: '圣诞节', holidayColor: true }
    	              ]
    	            },
    	          ]
    	        },
    	        {
    	          year: 2022,
    	          monthDate: [
    	            {
    	              month: 1,
    	              date: [
    	                { day: 1, text: '元旦', holidayColor: true },
    	                { day: 31, text: '除夕', holidayColor: true },
    	              ]
    	            },
    	            {
    	              month: 2,
    	              date: [
    	                { day: 14, text: '情人节', holidayColor: true },
    	                { day: 1, text: '春节', holidayColor: true },
    	                { day: 25, text: '元宵节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 4,
    	              date: [
    	                { day: 1, text: '愚人节', holidayColor: true },
    	                { day: 5, text: '清明节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 5,
    	              date: [
    	                { day: 1, text: '劳动节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 6,
    	              date: [
    	                { day: 1, text: '儿童节', holidayColor: true },
    	                { day: 3, text: '端午节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 8,
    	              date: [
    	                { day: 4, text: '七夕节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 9,
    	              date: [
    	                { day: 10, text: '教师节', holidayColor: true },
    	                { day: 10, text: '中秋节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 10,
    	              date: [
    	                { day: 1, text: '国庆节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 11,
    	              date: [
    	                { day: 11, text: '光棍节', holidayColor: true }
    	              ]
    	            },
    	            {
    	              month: 12,
    	              date: [
    	                { day: 24, text: '平安夜', holidayColor: true },
    	                { day: 25, text: '圣诞节', holidayColor: true }
    	              ]
    	            },
    	          ]
    	        },
    	      ]
    	      if (week === 6 || week === 7) day.weekendColor = true
    	      const yearObj = holiday.filter(item => item.year === year)[0]
    	      if (!yearObj) return day
    	      const monthObj = yearObj.monthDate.filter(item => item.month === month)[0]
    	      if (!monthObj) return day
    	      monthObj.date.forEach(item => {
    	        if (item.day === date) {
    	          day.text = item.text
    	          day.holidayColor = item.holidayColor
    	        }
    	      })
    	      return day;
    	    },
    	},
    	onClose() {
    	   this.setData({ showCal: false, showCalendar: false });
    	},
    	formatDate(date) {
    	  date = new Date(date);
    	  return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
    	},
      	onConfirm(event) {
    	    let date = this.formatDate(event.detail)
    	    let dateTime = new Date(date.replace(/-/g, '/')).getTime()
    	    this.setData({
    	      showCalendar: false,
    	      showCal: false,
    	      date: date,
    	    })
    	    const prevDate = util.formatDate(dateTime, 'yyyy-mm-dd')
    	    const prevDateName = util.formatDate(dateTime, 'yyyy年mm月dd日')
    	    this.setData({
    	      "dateName": prevDateName,
    	      "dateBox": prevDate,
    	      "dateTime": dateTime,
    	      "queryParam.dateStart": prevDate,
    	    })
    	    this.getList(this.data.queryParam)
      	},
      	onLoad: function (options) {
    	    if (options && options.dateTime) {
    	      var time = options.dateTime - 0
    	    } else {
    	      var time = new Date().getTime() - 24*60*60*1000
    	    }
    	    const prevDate = util.formatDate(time, 'yyyy-mm-dd')
    	    this.setData({
    	      "dateBox": prevDate,
    	      "dateTime": time,
    	      "queryParam.dateStart": prevDate,
    	    })
    	    this.getList(this.data.queryParam)
    	},
      	onReady: function () {
    	    setTimeout(() => {
    	      this.setData({
    	        // 控制日历组件显示
    	        asyncLoad: true,
    	        // 控制禁用
    	        asyncShow: true,
    	      })
    	  	}, 50)
    	}
    })
    
    /* components/watermark/watermark.json */
    {
      "navigationBarTitleText": "榜单",
      "usingComponents": {
        "ec-canvas": "../../../ec-canvas/ec-canvas",
        "van-calendar": "@vant/weapp/calendar/index",
        "van-cell": "@vant/weapp/cell/index",
        "van-button": "@vant/weapp/button/index"
      },
      "navigationBarBackgroundColor": "#E8380D",
      "navigationBarTextStyle": "white"
    }
    
    
    

    在这里插入图片描述

参考文章:
Vant Weapp官网
微信小程序:自定义组件的数据传递
微信小程序中自定义组件间通信传值
【微信小程序】自定义组件的使用+传值

日历以子组件的形式在具体页面使用(第二种方案)

<!--pages/boxOfficeModule/calendar/calendar.wxml-->
<van-calendar
  default-date="{{ defaultVal }}"
  poppable="{{ false }}"
  show-confirm="{{ false }}"
  style="--calendar-height: {{screenHeight}}"
  type="single"
  bind:confirm="onConfirm"
  min-date="{{ minDate }}"
  max-date="{{ maxDate }}"
  show-mark="{{ false }}"
  show-title="{{ false }}"
  formatter="{{ formatter }}" 
/>
// pages/boxOfficeModule/calendar/calendar.js
Component({

  /**
   * 页面的初始数据
   */
  properties: {
    date: {
      type: String,
      value: ''
    },
    platformIdIndex: {
      type: String,
      value: ''
    }
  },
  data: {
    date: '',
    show: false,
    minDate: new Date(2018, 0, 1).getTime(),
    maxDate: new Date().getTime(),
    defaultVal: new Date('2021-04-19').getTime(),
    formatter(day) {
      const year = day.date.getFullYear()
      const month = day.date.getMonth() + 1
      const date = day.date.getDate()
      let week = day.date.getDay()
      if (week === 0) week = 7
      const holiday = [
        {
          year: 2020,
          monthDate: [
            {
              month: 1,
              date: [
                { day: 1, text: '元旦', holidayColor: true },
                { day: 24, text: '除夕', holidayColor: true },
                { day: 25, text: '春节', holidayColor: true },
              ]
            },
            {
              month: 2,
              date: [
                { day: 14, text: '情人节', holidayColor: true },
                { day: 8, text: '元宵节', holidayColor: true }
              ]
            },
            {
              month: 4,
              date: [
                { day: 1, text: '愚人节', holidayColor: true },
                { day: 4, text: '清明节', holidayColor: true }
              ]
            },
            {
              month: 5,
              date: [
                { day: 1, text: '劳动节', holidayColor: true }
              ]
            },
            {
              month: 6,
              date: [
                { day: 1, text: '儿童节', holidayColor: true },
                { day: 25, text: '端午节', holidayColor: true }
              ]
            },
            {
              month: 8,
              date: [
                { day: 25, text: '七夕节', holidayColor: true }
              ]
            },
            {
              month: 9,
              date: [
                { day: 10, text: '教师节', holidayColor: true }
              ]
            },
            {
              month: 10,
              date: [
                { day: 1, text: '国庆节', holidayColor: true },
                { day: 1, text: '中秋节', holidayColor: true }
              ]
            },
            {
              month: 11,
              date: [
                { day: 11, text: '光棍节', holidayColor: true }
              ]
            },
            {
              month: 12,
              date: [
                { day: 24, text: '平安夜', holidayColor: true },
                { day: 25, text: '圣诞节', holidayColor: true }
              ]
            },
          ]
        },
        {
          year: 2021,
          monthDate: [
            {
              month: 1,
              date: [
                { day: 1, text: '元旦', holidayColor: true }
              ]
            },
            {
              month: 2,
              date: [
                { day: 14, text: '情人节', holidayColor: true },
                { day: 11, text: '除夕', holidayColor: true },
                { day: 12, text: '春节', holidayColor: true },
                { day: 26, text: '元宵节', holidayColor: true }
              ]
            },
            {
              month: 4,
              date: [
                { day: 1, text: '愚人节', holidayColor: true },
                { day: 4, text: '清明节', holidayColor: true }
              ]
            },
            {
              month: 5,
              date: [
                { day: 1, text: '劳动节', holidayColor: true }
              ]
            },
            {
              month: 6,
              date: [
                { day: 1, text: '儿童节', holidayColor: true },
                { day: 14, text: '端午节', holidayColor: true }
              ]
            },
            {
              month: 8,
              date: [
                { day: 14, text: '七夕节', holidayColor: true }
              ]
            },
            {
              month: 9,
              date: [
                { day: 10, text: '教师节', holidayColor: true },
                { day: 21, text: '中秋节', holidayColor: true }
              ]
            },
            {
              month: 10,
              date: [
                { day: 1, text: '国庆节', holidayColor: true }
              ]
            },
            {
              month: 11,
              date: [
                { day: 11, text: '光棍节', holidayColor: true }
              ]
            },
            {
              month: 12,
              date: [
                { day: 24, text: '平安夜', holidayColor: true },
                { day: 25, text: '圣诞节', holidayColor: true }
              ]
            },
          ]
        },
      ]
      if (week === 6 || week === 7) day.weekendColor = true
      const yearObj = holiday.filter(item => item.year === year)[0]
      if (!yearObj) return day
      const monthObj = yearObj.monthDate.filter(item => item.month === month)[0]
      if (!monthObj) return day
      monthObj.date.forEach(item => {
        if (item.day === date) {
          day.text = item.text
          day.holidayColor = item.holidayColor
        }
      })
      return day;
    },
    screenHeight: '600px',
    platformIdIndex: ''
  },
  methods: {
    onDisplay() {
      this.setData({ show: true });
    },
    onClose() {
      this.setData({ show: false });
    },
    formatDate(date) {
      date = new Date(date);
      return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
    },
    onConfirm(event) {
  
      let date = this.formatDate(event.detail)
      let dateTime = new Date(date.replace(/-/g, '/')).getTime()
      let platformIdIndex = this.data.platformIdIndex
      this.setData({
        show: false,
        date: date
      })
      console.log('event.detail', event)
      this.triggerEvent('dayChange', {
        dateTime: dateTime,
        platformIdIndex: platformIdIndex,
        showCalendar: false
      })
      // wx.reLaunch({
      //   url: '/pages/boxOfficeModule/boxOfficeList/boxOfficeList?dateTime=' + dateTime + '&platformIdIndex=' + platformIdIndex
      // })
    },
    computeScrollViewHeight() {
      let screenHeight = wx.getSystemInfoSync().windowHeight - 40
      this.setData({
        "screenHeight": screenHeight + 'px'
      })
    },
  },

  /**
   * 生命周期函数--监听页面加载
   */
   attached: function (options) {
    this.computeScrollViewHeight()
    console.log('this.properties', this.properties.date)
    console.log('new Date(this.properties.date).getTime()', new Date(this.properties.date).getTime())
    // if (options && options.date) {
    // this.setData({
    //   "date": this.properties.date,
    //   "defaultVal": new Date(this.properties.date).getTime(),
    //   "platformIdIndex": this.properties.platformIdIndex
    // })
    console.log('this.data.date', this.data.date, this.data.defaultVal)
    // }
  },
})
/* pages/boxOfficeModule/calendar/calendar.wxss */
.calendar {
  --calendar-height: 600px;
}
/* pages/boxOfficeModule/calendar/calendar.json */
{
  "navigationBarTitleText": "榜单",
  "navigationBarBackgroundColor": "#E8380D",
  "navigationBarTextStyle": "white",
  "usingComponents": {
    "van-calendar": "@vant/weapp/calendar/index",
    "van-cell": "@vant/weapp/cell/index",
    "van-button": "@vant/weapp/button/index"
  },
  "component": true
}
;