使用APICloud AVM框架封裝app日曆元件

海的盡頭發表於2022-04-07

實現的日曆效果圖

話不多說,上程式碼!

<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>

相關文章