1

实现的日历效果图

话不多说,上代码!

<template>
    <view class="page">
        <safe-area></safe-area>
        <view class="calendar-wrapper">
            <view class="calendar-toolbar">
                <text class="prev" onclick="prevMonth">〈</text>
                <text class="current">{{ currentDateStr }}</text>
                <text class="next" onclick="nextMonth">〉</text>
            </view>
            <view class="calendar-week">
                <text class="week-item" v-for="item of weekList" :key="item">{{ item }}</text>
            </view>
            <view class="calendar-inner">
                <text class="calendar-item" v-for="(item, index) of calendarList" :key="index" :class="this.changestyle(item.disable,item.value)"
                onclick="selDate" :data-val="item.value" :data-status="item.disable" :data-num="item.date">{{ item.date }}</text>
            </view>
        </view>
    </view>
</template>
<script>
    export default {
        name: 'calendar',
        installed(){
            this.setCurrent();
            this.calendarCreator();
        },
        data() {
            return{
                current:{},    
                weekList:['周日','周一','周二','周三','周四','周五','周六'],
                shareDate: new Date(),
                calendarList: [],
                seldate:'点击选择日期',
                selweek:'待定',
            }
        },
        computed: {
            // 显示当前时间
            currentDateStr() {
                let { year, month } = this.current;
                return `${year}年${this.pad(month + 1)}月`;
            }
        },
        methods: {
            selDate (e){
                // console.log(JSON.stringify(e.currentTarget.dataset.val));
                let status = e.currentTarget.dataset.status;
                let num = e.currentTarget.dataset.num;
                if(status){
                    this.data.seldate = e.currentTarget.dataset.val;
                    this.getWeek();
                    if(num>7){
                        this.prevMonth();
                    }
                    else{
                        this.nextMonth();
                    }
                }
                else{
                    this.data.seldate = e.currentTarget.dataset.val;
                    this.getWeek();
                    //重新加载一次日历 改变样式
                    this.calendarCreator();
                }
                this.fire('clickDate', this.data.seldate);
            },
            changestyle(status,date){
                if(status){
                    return 'calendar-item-disabled';
                }
                else{
                    if(date == this.data.seldate){
                        return 'calendar-item-checked';
                    }
                    else{
                        return 'calendar-item';
                    }
                }
            },
            // 判断当前月有多少天
            getDaysByMonth(year, month) {
                // console.log("本月多少天:"+new Date(year, month + 1, 0).getDate());
                return new Date(year, month + 1, 0).getDate();
            },
            getFirstDayByMonths(year, month) {
                // console.log("本月第一天周几:"+new Date(year, month, 1).getDay());
                return new Date(year, month, 1).getDay();
            },
            getLastDayByMonth(year, month) {
                // console.log("本月最后一天周几:"+new Date(year, month + 1, 0).getDay());
                return new Date(year, month + 1, 0).getDay();
            },
            // 对小于 10 的数字,前面补 0
            pad(str) {
                return str < 10 ? `0${str}` : str;
            },
            // 点击上一月
            prevMonth() {
                this.current.month--;
                // 因为 month的变化 会超出 0-11 的范围, 所以需要重新计算
                this.correctCurrent();
                // 生成新日期
                this.calendarCreator();
            },
            // 点击下一月
            nextMonth() {
                this.current.month++;
                // 因为 month的变化 会超出 0-11 的范围, 所以需要重新计算
                this.correctCurrent();
                // 生成新日期
                this.calendarCreator();
            },
            // 格式化时间,与主逻辑无关
            stringify(year, month, date) {
                let str = [year, this.pad(month + 1), this.pad(date)].join('-');
                return str;
            },
            // 设置或初始化 current
            setCurrent(d = new Date()) {
                let year = d.getFullYear();
                let month = d.getMonth();
                let date = d.getDate();
                this.current = {
                        year,
                        month,
                        date
                }
            },
            // 修正 current
            correctCurrent() {
                let { year, month, date } = this.data.current;
 
                let maxDate = this.getDaysByMonth(year, month);
                // 预防其他月跳转到2月,2月最多只有29天,没有30-31
                date = Math.min(maxDate, date);
 
                let instance = new Date(year, month, date);
                this.setCurrent(instance);
            },
            // 生成日期
            calendarCreator() {
                // 一天有多少毫秒
                const oneDayMS = 24 * 60 * 60 * 1000;
 
                let list = [];
                let { year, month } = this.data.current;
 
                // 当前月份第一天是星期几, 0-6
                let firstDay = this.getFirstDayByMonths(year, month);
                // 填充多少天                         
                let prefixDaysLen = firstDay === 0 ? 7 : firstDay;
                // 毫秒数
                let begin = new Date(year, month, 1).getTime() - oneDayMS * prefixDaysLen;
 
                // 当前月份最后一天是星期几, 0-6
                let lastDay = this.getLastDayByMonth(year, month);
                // 填充多少天, 和星期的排放顺序有关
                let suffixDaysLen = lastDay === 0 ? 6 : 6 - lastDay;
                // 毫秒数
                let end = new Date(year, month + 1, 0).getTime() + oneDayMS * suffixDaysLen;
 
                while (begin <= end) {
                        // 享元模式,避免重复 new Date
                        this.data.shareDate.setTime(begin);
                        let year = this.data.shareDate.getFullYear();
                        let curMonth = this.data.shareDate.getMonth();
                        let date = this.data.shareDate.getDate();
                        list.push({
                                year: year,
                                month: curMonth,
                                date: date,
                                disable: curMonth !== month,
                                value: this.stringify(year, curMonth, date)
                        });
                        begin += oneDayMS;
                }
                this.data.calendarList = list;            
                // console.log(JSON.stringify(this.data.calendarList));
            },
            //获取选中日期的周几
            getWeek(){
                let index =new Date(this.data.seldate).getDay();
                let weekArr = ['星期天', '星期一', '星期二', '星期三', '星期四', '星期五','星期六'];
                let week = weekArr[index];
                this.data.selweek = week;
            },
        }
    }
</script>
<style>
    .page {
        height: 100%;
    }
    .calendar-wrapper {
        margin: 10px 10px 0 10px;
        background-color:#3c40c6;
        border-top-left-radius: 10px;
        border-top-right-radius: 10px;
        max-height: 400px;
    }
 
    .calendar-toolbar {
        padding: 10px 10px;
        flex-flow: row nowrap;
        justify-content: space-between;
        align-items: center;        
        border-bottom: 1px solid #fff;
    }
    .prev{
        flex: 1;
        text-align: center;
        color: #fff;
    }
    .current {
        flex: 1;
        text-align: center;
        color: #fff;
    }
    .next{
        flex: 1;
        text-align: center;
        color: #fff;
    }
 
    .calendar-week {
        padding: 5px 10px;
        flex-flow: row nowrap;
        justify-content: space-around;
        align-items: center;
    }
    .week-item { 
        padding: 5px;
        font-weight: bolder;
        font-size: 12px;
        color: #fff;
    }
    .calendar-inner{
        padding: 10px 10px;
        flex-flow: row wrap;
        justify-content: space-around;
        align-items: center;
    }
    .calendar-item {
        width:14%;
        font-weight: bolder;
        text-align: center;
        font-size: 15px;
        color: #fff;
        padding: 5px;
        background-color: #3c40c6;
    }
    .calendar-item-disabled {
        width:14%;
        font-weight: bolder;
        text-align: center;
        font-size: 15px;
        color: #999;
    }
    .calendar-item-checked {
        width:14%;
        font-weight: bolder;
        text-align: center;
        font-size: 15px;
        color: #000000;
        background-color: #ffffff;
        border-radius: 5px;
    }
</style>

其他页面引用

<template>
    <view class="page">
        <calendar onclickDate="getSelDate"></calendar>
        <view>
            <text>当前日期是</text>
            <text>{today}</text>
        </view>
    </view>
</template>
<script>
    import '../../components/calendar.stml'  
    export default {
        name: 'test',
        apiready(){
            
        },
        data() {
            return{
                today:''
            }
        },
        methods: {
            getSelDate(e){
                console.log(JSON.stringify(e));
                this.data.today = e.detail;
                api.toast({
                    msg:'当前选中日期是:'+e.detail
                })
            }
        }
    }
</script>
<style>
    .page {
        height: 100%;
    }
</style>

现在,APICloud 官方正在举办 AVM 组件的征集大赛,通过审核就能获得一定的奖金,大家感兴趣的也可以去围观一下。传送门:https://www.apicloud.com/acti...


海的尽头
18 声望340 粉丝