小程序基础-自定义日历组件

这是我参与8月更文挑战的第2天,活动详情查看:8月更文挑战

如下图要实现如下的日历,可以切换月份,默认显示当前月,有事件的日期下面有一个小点,今天之前的日期不可选,小点是灰色的,今天之后的日期可以选择。

1.png

原本想直接用vant的van-calendar的,但是完全不符合需要,无奈只能自己动手了,代码比较冗余,自己记录一下,温故而知新!

1.月份日历渲染

  • 父组件的wxml
<van-popup show="{{ show }}" round position="bottom" custom-style="height: 55%" bind:close="onClose" closeable>
    <the-calendar bindonCalendarClose="onCalendarClose"></the-calendar>
</van-popup>
复制代码
  • 日历组件的wxml
<view class="calendar-container">
    <view class="top-title">
        <text class="fs16 black">测试时间</text>
    </view>
    <view class="choose-month">
        <view class="month-left">
            <view class="left-par">
                <text class="iconfont iconxiangyou" bindtap="chooseMonth" data-state="-1"></text>
            </view>
            <text class="title">{{year}}年{{month}}月</text>
            <view class="right-par">
                <text class="iconfont icongengduo" bindtap="chooseMonth" data-state="1"></text>
            </view>
        </view>
    </view>
    <view class="days-area">
        <view class="day week black-65 fs12" wx:for="{{weeks}}" wx:key="index">{{item}}</view>
        <view wx:for="{{days}}" wx:key="index" wx:for-item="day"
            class="day day-time fs12 {{day.chooseDay?'choose-day' : ''}} {{day.className}} {{day.event?'day-event':''}}"
            bindtap="chooseThisDay" data-year="{{day.year}}" data-month="{{day.month}}"
            data-gregorian="{{day.gregorian}}" data-className="{{day.className}}">{{day.title}}</view>
    </view>
</view>
复制代码

2.日历事件渲染

// 获取当前月份所有日期
getDays() {
    this.data.days = [];
    const day = new Date();
    day.setFullYear(this.data.year, this.data.month - 1, 1); // 获取当月第一天(月份减1)
    const month = new Date();
    month.setFullYear(this.data.year, this.data.month, 0); // 获取当月最后一天
    const prevMonth = new Date();
    prevMonth.setFullYear(this.data.year, this.data.month - 1, 0); // 获取上月
    let prevDay = prevMonth.getDate(); // 上月的日期
    let nextMonth = new Date();
    nextMonth = new Date(this.data.year, this.data.month, 0); // 下月的日期
    let nextDay = nextMonth.getDay(); // 最后一天星期几
    for (let i = day.getDay() + 1; i > 1; i--) { // 当月第一天距离所在周周一(+1周日)的空白占位
        let prevM = this.data.month - 1,
            prevYear = this.data.year;
        if (prevM < 1) {
            prevM = 12;
            prevYear = prevYear - 1
        }
        this.data.days.unshift({
            year: prevYear,
            month: prevM,
            title: prevDay,
            gregorian: prevDay,
            className: 'grey'
        })
        prevDay--;
    }
    for (let i = 1; i <= month.getDate(); i++) { // 获取当月天数填充日历
        let title = i;
        if (this.data.year === this.data.yearNow && this.data.month === this.data.monthNow && this.data.todayNow === i) {
            title = '今';
        } ;
        this.data.days.push({
            year: this.data.year,
            month: this.data.month,
            title: title,
            gregorian: i,
            className: 'grey'
        })
    }
    let j = 0,
        nextM = this.data.month + 1,
        nextY = this.data.year;
    if (nextM > 12) {
        nextM = 1;
        nextY = nextY + 1;
    }
    for (let i = nextDay + 1; i < 7; i++) { // 当月最后一天距离所在周周六的空白占位
        j++;
        this.data.days.push({
            year: nextY,
            month: nextM,
            title: j,
            gregorian: j,
            className: 'grey'
        })
        nextDay++;
    }
    // 日期的选中效果
    this.data.days.forEach((itemD) => {
        if (this.data.chooseDate.year === itemD.year && this.data.chooseDate.month === itemD.month && this.data.chooseDate.gregorian === itemD.gregorian) {
            itemD.chooseDay = true;
        }
    })
    this.setData({
        days: this.data.days
    })
},
// 改变年份
chooseYears(state) {
    this.setData({
        year: this.data.year += state
    })
    this.getDays();
    this.getEventsList('change-month'); // 获取事件
},
// 改变月份
chooseMonth(event) {
    let state = event.currentTarget.dataset.state;
    this.setData({
        month: this.data.month += Number(state)
    })
    // 月份 年份变化
    if (this.data.month < 1) {
        this.setData({
            month: 12
        })
        this.chooseYears(-1)
    } else if (this.data.month > 12) {
        this.setData({
            month: 1
        })
        this.chooseYears(1);
    } else {
        this.getDays();
    }
    this.getEventsList('change-month'); //月事件
},
复制代码

3.以今天为分界,渲染事件

// 获取月事件
getEventsList(flag) {
    let obj = {
        starDate: this.data.starDate,
        endDate: this.data.endDate,
        resId: this.data.resId,
    }
    $post(getCalendarBoardByResId, obj).then(res => {
        this.getEventData(res);
    })
},
// 处理事件数据结构
getEventData(newData) {
    let nowDate = new Date().getTime() - 8.64e7;
    if (newData.length > 0) {
        newData.forEach((itemN) => {
            this.data.days.forEach((itemD) => {
                if (itemN.year === itemD.year &&
                    itemN.month === itemD.month &&
                    itemN.day === itemD.gregorian
                ) {
                    itemD.event = true;
                    let thisDate = new Date(itemD.year + '-' + this.addZero(itemD.month) + '-' + this.addZero(itemD.gregorian)).getTime();
                    if (thisDate >= nowDate) { // 今天以后的日期可点击
                        itemD.className = '';
                    }
                }
            })
        })
    } else {
        this.data.days.forEach((itemD) => {
            itemD.event = false;
        })
    }
    this.setData({
        days: this.data.days
    })
},
复制代码

4.日期的点击事件

// 选择某天 
chooseThisDay(e) {
    // 点击今天之前的日期 不可点击
    if (e.currentTarget && e.currentTarget.dataset && e.currentTarget.dataset.classname == 'grey') {
        return;
    }
    let day = e.currentTarget.dataset;
    let flag = 0;
    this.data.days.forEach((itemD) => {
        itemD.chooseDay = false;
        if (day.year === itemD.year && day.month === itemD.month && day.gregorian === itemD.gregorian) {
            if (itemD.className === 'grey') {
                flag++;
            } else {
                itemD.chooseDay = true; // 选中
            }
        }
        if (this.data.yearNow === itemD.year && this.data.monthNow === itemD.month && this.data.todayNow === itemD.gregorian) {
            itemD.isToday = true; // 今天
        }
    })
    if (flag > 0) {
        return false;
    }
 
    this.setData({
        today: day.gregorian,
        chooseDate: {
            year: day.year,
            month: day.month,
            gregorian: day.gregorian
        },
        days: this.data.days
    })
    // 父级回调
    this.triggerEvent('onCalendarClose', {
        year: day.year,
        month: day.month,
        gregorian: day.gregorian
    });
},
复制代码

好了,以上就是日历组件的全部代码啦。感谢观看!

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享