需求:
小程序需要实现日历的需求,可以单选、可以选择区间、节假日和周六颜色高亮、返回本月。具体如图,类似猫眼app的日历选择。
思路:
- 参考市场上含有日历的小程序及app,确定是自己实现还是使用组件,骨朵使用的是Pikaday。
- 确定使用Vant Weapp组件库中日历。
- 需要对源码进行一些修改,首先样式的修改、包括顶部周日到周六、节假日及周六日日期的颜色、返回本月按钮的添加及样式。
- 前后实现了三种展示日历的不同方式
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图可能渲染一半,不考虑图的渲染体验,等到日历组件渲染完成后继续加载图表。此时再去点击日期选择就可以使用了。以下实现步骤为该种方案 - 比较好的实现方式应该对这种需要渲染上千个数据的进行虚拟加载,这样就会避免了加载时间过长导致的种种问题。但由于使用的组件,暂时没有实现。
步骤:
-
修改样式及组件的属性配置
下图是下载好的组件库,删掉了没有用的组件
将日历中的日期进行三种展示,分别是,普通日期、节假日、周六日
添加返回本月按钮,以及返回本月对应的方法,在开发者工具上好用,但体验版上不好使
后续删掉了整个按钮,具体问题没有分析
-
修改样式及组件的属性配置
<!--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
}