好用的微信小程序日历组件(可滑动,可展开收缩,可标点)

html5 文章 2022-07-15 14:19 0 全屏看文

效果图

组件介绍

原生小程序编写,简单轻便,拿来即用。
gitee地址:https://gitee.com/qq_connect-EC6BCC0B556624342/wx-calendar

代码部分(这里可能不是最新的推荐去gitee克隆代码)

calendar.wxml

<!--component/calendar/calendar.wxml--><view class="calendar">    <view class="title">        <view class="header-wrap">            <view class="flex">   <view class="title">{{title}}</view>   <view class="month">       <block wx:if="{{title}}">           (       </block>       {{selectDay.year}}年{{selectDay.month}}月       <block wx:if="{{title}}">           )       </block>   </view>            </view>            <block wx:if="{{goNow}}">   <view wx:if="{{open && !(nowDay.year==selectDay.year&&nowDay.month==selectDay.month&&nowDay.day==selectDay.day)}}" class="today" bindtap="switchNowDate">       今日   </view>            </block>        </view>    </view>    <!-- 日历头部 -->    <view class="flex-around calendar-week">        <view class="view">一</view>        <view class="view">二</view>        <view class="view">三</view>        <view class="view">四</view>        <view class="view">五</view>        <view class="view">六</view>        <view class="view">日</view>    </view>    <!-- 日历主体 -->    <swiper class="swiper" style="height:{{swiperHeight}}rpx" bindchange="swiperChange" circular="{{true}}" current="{{swiperCurrent}}" duration="{{swiperDuration}}">        <swiper-item wx:for="{{[dateList0, dateList1, dateList2]}}" wx:for-index="listIndex" wx:for-item="listItem" wx:key="listIndex">            <view class="flex-start flex-wrap calendar-main" style="height:{{listItem.length/7*82}}rpx">   <view wx:for="{{listItem}}" wx:key="dateList" class="day">       <view class="bg {{item.month === selectDay.month?spotMap['y'+item.year+'m'+item.month+'d'+item.day]?spotMap['y'+item.year+'m'+item.month+'d'+item.day]:'':''}} {{(item.year === nowDay.year && item.month === nowDay.month && item.day === nowDay.day) ? 'now' : ''}} {{(item.year === selectDay.year && item.month === selectDay.month) ? (item.day === selectDay.day && oldCurrent === listIndex ?'select':''): 'other-month'}}" catchtap="selectChange" data-day="{{item.day}}" data-year="{{item.year}}" data-month="{{item.month}}">           {{item.day}}       </view>   </view>            </view>        </swiper-item>    </swiper>    <view catchtap="openChange" class="flex list-open">        <view class="icon {{open?'fold':'unfold'}}"></view>    </view></view>

calendar.js

// component/calendar/calendar.jsComponent({    /**     * 组件的属性列表     */    properties: {        spotMap: { //标点的日期            type: Object,            value: {}        },        defaultTime: { //标记的日期,默认为今日            type: String,            value: ''        },        title: { //标题            type: String,            value: ''        },        goNow: { // 是否有快速回到今天的功能            type: Boolean,            value: true,        }    },    /**     * 组件的初始数据     */    data: {        selectDay: {}, //选中时间        nowDay: {}, //现在时间        open: false,        swiperCurrent: 1, //选中时间        oldCurrent: 1, //之前选中时间        dateList0: [], //0位置的日历数组        dateList1: [], //1位置的日历数组        dateList2: [], //2位置的日历数组        swiperDuration: 500,        swiperHeight: 0,        backChange: false, //跳过change切换    },    /**     * 组件的方法列表     */    methods: {        swiperChange(e) { // 日历滑动时触发的方法            if (this.data.backChange) {   this.setData({       backChange: false   })   return            }            //计算第三个索引            let rest = 3 - e.detail.current - this.data.oldCurrent            let dif = e.detail.current - this.data.oldCurrent            let date            if (dif === -2 || (dif > 0 && dif !== 2)) { //向右划的情况,日期增加   if (this.data.open) {       date = new Date(this.data.selectDay.year, this.data.selectDay.month)       this.setMonth(date.getFullYear(), date.getMonth() + 1, undefined)       this.getIndexList({           setYear: this.data.selectDay.year,           setMonth: this.data.selectDay.month,           dateIndex: rest       })   } else {       date = new Date(this.data.selectDay.year, this.data.selectDay.month - 1, this.data.selectDay.day + 7)       this.setMonth(date.getFullYear(), date.getMonth() + 1, date.getDate())       this.getIndexList({           setYear: this.data.selectDay.year,           setMonth: this.data.selectDay.month - 1,           setDay: this.data.selectDay.day + 7,           dateIndex: rest       })   }            } else { //向左划的情况,日期减少   if (this.data.open) {       date = new Date(this.data.selectDay.year, this.data.selectDay.month - 2)       this.setMonth(date.getFullYear(), date.getMonth() + 1, undefined)       this.getIndexList({           setYear: this.data.selectDay.year,           setMonth: this.data.selectDay.month - 2,           dateIndex: rest       })   } else {       date = new Date(this.data.selectDay.year, this.data.selectDay.month - 1, this.data.selectDay.day - 7)       this.setMonth(date.getFullYear(), date.getMonth() + 1, date.getDate())       this.getIndexList({           setYear: this.data.selectDay.year,           setMonth: this.data.selectDay.month - 1,           setDay: this.data.selectDay.day - 7,           dateIndex: rest       })   }            }            this.setData({   oldCurrent: e.detail.current            })            this.setSwiperHeight(e.detail.current)        },        setSwiperHeight(index) { // 根据指定位置数组的大小计算长度            this.setData({   swiperHeight: this.data[`dateList${index}`].length / 7 * 82 + 18            })        },        //更新指定的索引和月份的列表        getIndexList({            setYear,            setMonth,            setDay = void 0,            dateIndex        }) {            let appointMonth            if (setDay)   appointMonth = new Date(setYear, setMonth, setDay)            else   appointMonth = new Date(setYear, setMonth)            let listName = `dateList${dateIndex}`            this.setData({   [listName]: this.dateInit({       setYear: appointMonth.getFullYear(),       setMonth: appointMonth.getMonth() + 1,       setDay: appointMonth.getDate(),       hasBack: true   }),            })        },        //设置月份        setMonth(setYear, setMonth, setDay) {            const day = Math.min(new Date(setYear, setMonth, 0).getDate(), this.data.selectDay.day)            if (this.data.selectDay.year !== setYear || this.data.selectDay.month !== setMonth) {   const data = {       selectDay: {           year: setYear,           month: setMonth,           day: setDay ? setDay : day       },   }   if (!setDay) {       data.open = true   }   this.setData(data, () => {       this.triggerEvent("selectDay", this.data.selectDay)   })            } else {   const data = {       selectDay: {           year: setYear,           month: setMonth,           day: setDay ? setDay : day       },   }   this.setData(data, () => {       this.triggerEvent("selectDay", this.data.selectDay)   })            }        },        //展开收起        openChange() {            this.setData({   open: !this.data.open            })            this.triggerEvent("aaa", {   a: 0            })            // 更新数据            const selectDate = new Date(this.data.selectDay.year, this.data.selectDay.month - 1, this.data.selectDay.day)            if (this.data.oldCurrent === 0) {   this.updateList(selectDate, -1, 2)   this.updateList(selectDate, 0, 0)   this.updateList(selectDate, 1, 1)            } else if (this.data.oldCurrent === 1) {   this.updateList(selectDate, -1, 0)   this.updateList(selectDate, 0, 1)   this.updateList(selectDate, 1, 2)            } else if (this.data.oldCurrent === 2) {   this.updateList(selectDate, -1, 1)   this.updateList(selectDate, 0, 2)   this.updateList(selectDate, 1, 0)            }            this.setSwiperHeight(this.data.oldCurrent)        },        // 选中并切换今日日期        switchNowDate() {            const now = new Date()            const selectDate = new Date(this.data.selectDay.year, this.data.selectDay.month - 1, this.data.selectDay.day)            let dateDiff = (selectDate.getFullYear() - now.getFullYear()) * 12 + (selectDate.getMonth() - now.getMonth())            let diff = dateDiff === 0 ? 0 : dateDiff > 0 ? -1 : 1            const diffSum = (x) => (3 + (x % 3)) % 3            if (this.data.oldCurrent === 0) {   this.updateList(now, -1, diffSum(2 + diff))   this.updateList(now, 0, diffSum(0 + diff))   this.updateList(now, 1, diffSum(1 + diff))            } else if (this.data.oldCurrent === 1) {   this.updateList(now, -1, diffSum(0 + diff))   this.updateList(now, 0, diffSum(1 + diff))   this.updateList(now, 1, diffSum(2 + diff))            } else if (this.data.oldCurrent === 2) {   this.updateList(now, -1, diffSum(1 + diff))   this.updateList(now, 0, diffSum(2 + diff))   this.updateList(now, 1, diffSum(0 + diff))            }            this.setData({   swiperCurrent: diffSum(this.data.oldCurrent + diff),   oldCurrent: diffSum(this.data.oldCurrent + diff),   backChange: dateDiff !== 0,            })            this.setData({   selectDay: {       year: now.getFullYear(),       month: now.getMonth() + 1,       day: now.getDate()   }            }, () => {   this.triggerEvent("selectDay", this.data.selectDay)            })            this.setSwiperHeight(this.data.oldCurrent)        },        //日历主体的渲染方法        dateInit({            setYear,            setMonth,            setDay = this.data.selectDay.day,            hasBack = false        } = {            setYear: this.data.selectDay.year,            setMonth: this.data.selectDay.month,            setDay: this.data.selectDay.day,            hasBack: false        }) {            let dateList = []; //需要遍历的日历数组数据            let now = new Date(setYear, setMonth - 1) //当前月份的1号            let startWeek = now.getDay(); //目标月1号对应的星期            let resetStartWeek = startWeek == 0 ? 6 : startWeek - 1; //重新定义星期将星期天替换为6其余-1            let dayNum = new Date(setYear, setMonth, 0).getDate() //当前月有多少天            let forNum = Math.ceil((resetStartWeek + dayNum) / 7) * 7 //当前月跨越的周数            let selectDay = setDay ? setDay : this.data.selectDay.day            this.triggerEvent("getDateList", {   setYear: now.getFullYear(),   setMonth: now.getMonth() + 1            })            if (this.data.open) {   //展开状态,需要渲染完整的月份   for (let i = 0; i < forNum; i++) {       const now2 = new Date(now)       now2.setDate(i - resetStartWeek + 1)       let obj = {};       obj = {           day: now2.getDate(),           month: now2.getMonth() + 1,           year: now2.getFullYear()       };       dateList[i] = obj;   }            } else {   //非展开状态,只需要渲染当前周   for (let i = 0; i < 7; i++) {       const now2 = new Date(now)       //当前周的7天       now2.setDate(Math.ceil((selectDay + (startWeek - 1)) / 7) * 7 - 6 - (startWeek - 1) + i)       let obj = {};       obj = {           day: now2.getDate(),           month: now2.getMonth() + 1,           year: now2.getFullYear()       };       dateList[i] = obj;   }            }            if (hasBack) {   return dateList            }            this.setData({   dateList1: dateList            })        },        //一天被点击时        selectChange(e) {            const year = e.currentTarget.dataset.year            const month = e.currentTarget.dataset.month            const day = e.currentTarget.dataset.day            const selectDay = {   year: year,   month: month,   day: day,            }            if (this.data.open && (this.data.selectDay.year !== year || this.data.selectDay.month !== month)) {   if ((year * 12 + month) > (this.data.selectDay.year * 12 + this.data.selectDay.month)) { // 下个月       if (this.data.oldCurrent == 2)           this.setData({  swiperCurrent: 0           })       else           this.setData({  swiperCurrent: this.data.oldCurrent + 1           })   } else { // 点击上个月       if (this.data.oldCurrent == 0)           this.setData({  swiperCurrent: 2           })       else           this.setData({  swiperCurrent: this.data.oldCurrent - 1           })   }   this.setData({       ['selectDay.day']: day   }, () => {       this.triggerEvent("selectDay", this.data.selectDay)   })            } else if (this.data.selectDay.day !== day) {   this.setData({       selectDay: selectDay   }, () => {       this.triggerEvent("selectDay", this.data.selectDay)   })            }        },        updateList(date, offset, index) {            if (this.data.open) { //打开状态   const setDate = new Date(date.getFullYear(), date.getMonth() + offset * 1) //取得当前日期的上个月日期   this.getIndexList({       setYear: setDate.getFullYear(),       setMonth: setDate.getMonth(),       dateIndex: index   })            } else {   const setDate = new Date(date.getFullYear(), date.getMonth(), date.getDate() + offset * 7) //取得当前日期的七天后的日期   this.getIndexList({       setYear: setDate.getFullYear(),       setMonth: setDate.getMonth(),       setDay: setDate.getDate(),       dateIndex: index   })            }        },    },    lifetimes: {        attached() {            let now = this.data.defaultTime ? new Date(this.data.defaultTime) : new Date()            let selectDay = {   year: now.getFullYear(),   month: now.getMonth() + 1,   day: now.getDate()            }            this.setData({   nowDay: {       year: now.getFullYear(),       month: now.getMonth() + 1,       day: now.getDate()   }            })            this.setMonth(selectDay.year, selectDay.month, selectDay.day)            this.updateList(now, -1, 0)            this.updateList(now, 0, 1)            this.updateList(now, 1, 2)            this.setSwiperHeight(1)        }    },    observers: {}})

calendar.json

{    "component": true,    "usingComponents": {}}

calendar.wxss

/* component/calendar/calendar.wxss */.icon {  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACcUlEQVRYhe2WvWtUURDFf8dNVk1ETViMX4WNna22CopELBQUkYASgzFFUPBPsLGSgAqJGDRGBEUsRA0KIthaip2I/4CEoIR8JyP33lldl7fuR1AL9xSP3Xfvmzlz7pl5jyaa+O+hq0NDqDEV8sBGYA3wDZirP4TFhxvFApAD1gPz5TGqF2Xx2pK5puwA9uuPPUA30A48Bd43Ukg2gWpQTHwe2Iax5GRuA6//BoFuwQDQaUF6xaPYBFzCYryXf4yAoAc44We/INjgJvzqGwYwWg2e1Rqzogmt9MwTjgGngBXvgLB8Axh1HyiuiV7BwVoJ1KpAqPqMu70dtFbYNWDC7SqwfoMp0r9BLHbHi2qBa2nDk0A/aAmUF9oscR1pAikJIR4g3RXqUFIoxD0nOLQqAoLjwFlgOuyVKCDGve3KMY54BOqMrBTVDSQON0rgqLfajJCF5IJ7SmdeifBIICgISgQSbUCPYH+9BI4Ag8BidLzY4VXf+V01TmIM9BhU8Gc7gNOCfVn7s0y4N1SuNNuXhbYDDwU3qyX/QUIMm7Eo6HNj7gQueKe8KyfQ4guh2gPAZW+zWdAW4Al1JC+RYjTMBKA3xYpdcZE0O974rlxIXvDeDhv6gF1Kg6UrnrcYqTv5TwwLpi0VFRTd6oTmQB/AckUPrMS5LjpR9MU6n+2rSV7EfRQH1orSwOoC2w0WlQ+XZZ9qs/57CnQFLMnk47A4FdXYx8MYMJl8ECN9hPgSyxdNGM7qC3DLibyt9Ea3rHtmFddK8DzlURvYZ1c5GrA4ueZBr5S8EPp3JjNgyc061QgvsE9gk/4x0+qKN9FEE/8QwHd9qo6ectzgFAAAAABJRU5ErkJggg==");  background-size: 100% auto;  width: 32rpx;  height: 32rpx;}.flex {  display: flex;  justify-content: space-between;  align-items: center;}.swiper {  transition: height 0.3s;}.header-wrap {  display: flex;  justify-content: space-between;  align-items: center;}.today {  width: 88rpx;  height: 42rpx;  background: #F3F4F4;  border-radius: 22rpx;  font-size: 24rpx;  line-height: 42rpx;  color: #868D8D;  text-align: center;  margin-right: 6rpx;}.today:active {  background: #dfdfdf;  color: #5f6464;}.direction-column {  flex-direction: column;}.flex1 {  flex: 1;}.flex-center {  display: flex;  justify-content: center;  align-items: center;}.flex-start {  display: flex;  justify-content: flex-start;  align-items: center;}.flex-end {  display: flex;  justify-content: flex-end;  align-items: center;}.flex-around {  display: flex;  justify-content: space-around;  align-items: center;}.flex-wrap {  flex-wrap: wrap;}.align-start {  align-items: flex-start;}.align-end {  align-items: flex-end;}.align-stretch {  align-items: stretch;}.calendar {  font-family: "PingFang SC", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", Helvetica, Arial, "Hiragino Sans GB", "Source Han Sans", "Noto Sans CJK Sc", "Microsoft YaHei", "Microsoft Jhenghei", sans-serif;}.calendar .title {  padding: 10rpx 16rpx 10rpx 20rpx;  line-height: 60rpx;  font-size: 32rpx;  font-weight: 600;  color: #1C2525;  line-height: 44px;  letter-spacing:1px;}.calendar .title .year-month {  margin-right: 20rpx;}.calendar .title .icon {  padding: 0 16rpx;  font-size: 32rpx;  color: #999;}.calendar .title .open {  background-color: #f6f6f6;  color: #999;  font-size: 22rpx;  line-height: 36rpx;  border-radius: 18rpx;  padding: 0 14rpx;}.list-open {  position: relative;  justify-content: center;}.list-open .icon::after {  content: '';  position: absolute;  top: 16rpx;  right: 60rpx;  display: block;  width: 278rpx;  height: 0rpx;  border-bottom: 2rpx solid rgba(214, 219, 219, 0.68);}.list-open .icon::before {  content: '';  position: absolute;  top: 16rpx;  left: 60rpx;  display: block;  width: 278rpx;  height: 0rpx;  border-bottom: 2rpx solid rgba(214, 219, 219, 0.68);}.fold {  transform: rotate(0deg);}.unfold {  transform: rotate(180deg);}.calendar .calendar-week {  line-height: 40rpx;  padding: 0 25rpx;  font-size: 28rpx;  color: #999;}.calendar .calendar-week .view {  width: 100rpx;  text-align: center;}.calendar .calendar-main {  padding: 18rpx 25rpx 0rpx;  transition: height 0.3s;  align-content: flex-start;  overflow: hidden;}.calendar .calendar-main .day {  position: relative;  width: 100rpx;  color: #666;  text-align: center;  height: 82rpx;}.calendar .calendar-main .day .bg {  height: 66rpx;  line-height: 66rpx;  font-size: 28rpx;  color: #333;}.calendar .calendar-main .day .now {  width: 66rpx;  border-radius: 50%;  text-align: center;  color: #0EC0B8;  background: rgba(14, 192, 184, 0.2);  margin: 0 auto;}.calendar .calendar-main .day .select {  width: 66rpx;  border-radius: 50%;  text-align: center;  color: #fff;  background: #0EC0B8;  margin: 0 auto;}.calendar .calendar-main .day .spot::after {  position: absolute;  content: "";  display: block;  width: 8rpx;  height: 8rpx;  bottom: 22rpx;  background: #0EC0B8;  border-radius: 50%;  left: 0;  right: 0;  margin: auto;}.calendar .calendar-main .day .deep-spot::after {  position: absolute;  content: "";  display: block;  width: 8rpx;  height: 8rpx;  bottom: 22rpx;  background: #FF7416;  border-radius: 50%;  left: 0;  right: 0;  margin: auto;}.calendar .calendar-main .day .other-month {  color: #ccc;}.header-wrap .month {  font-size: 28rpx;  color: #929797;  line-height: 40rpx;}
-EOF-