如何使用vue编写一个简单的日历组件

直接先把我的代码贴上

1.CSS

 * {
        margin: 0;
        padding: 0;
        list-style: none;
        font-size: 16px;
    }

    #calendar {
        width: 50%;
        margin: 120px auto;
        padding: 10px;
        /* background: #ccc; */
        border-radius: 5px;
        overflow: hidden;
        background: #28a1ff;

    }

    .month {
        background: #28a1ff;
        color: #fff;
        height: 32px;
        margin: 0 auto;
        padding: 0 10px;
    }

    .month ul {
        margin: 0 auto;
        height: 32px;
        width: 90%;
        display: flex;
        align-items: center;
        justify-content: space-between;
    }

    .month ul li {
        cursor: pointer;
    }

    .arrow {
        width: 32px;
        text-align: center;
    }

    .weekdays,
    .days {
        display: grid;
        grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
        align-items: center;
        justify-items: center;
        padding: 10px 10px;
    }

    .weekdays {
        grid-template-rows: 32px;
        background: #28a1ff;
        color: #fff;
    }

    .days {
        grid-template-rows: 32px 32px 32px 32px 32px;
        background-color: #0986e7;
        color: #fff;
        padding-top: 10px;
        border-radius: 5px;
    }

    .days li {
        width: 100%;
        height: 100%;
        display: flex;
        align-items: center;
        justify-items: center;
    }

    .days li span {
        width: 100%;
        height: 100%;
        text-align: center;
        line-height: 32px;
    }

    .other-month {
        color: #ccc;
    }

    .active {
        background: #28a1ff;
        border-radius: 5px;
    }

    .this-month:hover {
        cursor: pointer;
        background: #28a1ff;
        border-radius: 5px;
    }

    .year-container,
    .month-container {
        background: #fff;
        padding: 10px;
        border-radius: 5px;
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;
        grid-gap: 5px;
        width: 240px;
        position: fixed;
    }

    .year-container span,
    .month-container span {
        text-align: center;
        cursor: pointer;
    }

    .year-container span:hover,
    .month-container span:hover {
        color: #28a1ff;
    }

    .isYear,
    .isMonth {
        color: #28a1ff;
    }

2.HTML

<div id="calendar" ref="calendar">
        <!-- 年份 月份 -->
        <div class="month">
            <ul>
                <!--点击会触发pickpre函数,重新刷新当前日期 @click(vue v-on:click缩写) -->
                <li class="arrow" @click="pickPre(currentYear,currentMonth)"></li>
                <li class="year-month">
                    <span class="choose-year"
                        @click="pickYear(currentYear,currentMonth,1,$event)">{{ currentYear }}年</span>
                    <span class="choose-month"
                        @click="pickYear(currentYear,currentMonth,2,$event)">{{ currentMonth }}月</span>
                    <span>{{currentDay}}日</span>
                </li>
                <li class="arrow" @click="pickNext(currentYear,currentMonth)"></li>
            </ul>
        </div>
        <!-- 星期 -->
        <ul class="weekdays">
            <li></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
        </ul>
        <!-- 日期 -->
        <ul class="days">
            <!-- 核心 v-for循环 每一次循环用<li>标签创建一天 -->
            <li v-for="dayobject in days" @click="changeDay(dayobject)" :key="dayobject.id"
                :class="[{'other-month':!dayobject.isThisMonth},{'active':dayobject.isThisDay},{'this-month':dayobject.isThisMonth}]">
                <span>{{ dayobject.day.getDate() }}</span>
            </li>
        </ul>
        <div class="year-container" ref="container" v-if="showYearList">
            <span v-for="(item,index) in yearList" :class="item==currentYear?'isYear':''" @click="selectYear(item)">{{item}}</span>
        </div>
        <div class="month-container" ref="container" v-if="showMonth">
            <span v-for="(item,index) in month" :class="item==currentMonth?'isMonth':''" @click="selectMonth(item)">{{item}}</span>
        </div>
    </div>

3.Script

var myVue = new Vue({
            el: '#calendar',
            data: {
                currentDay: new Date().getDate(),
                currentMonth: new Date().getMonth() + 1,
                currentYear: new Date().getFullYear(),
                currentWeek: 1,
                days: [],
                yearList: [],
                showYearList: false,
                month: null,
                showMonth: false
            },
            created: function () { //在vue初始化时调用
                var d = new Date()
                this.initData(this.formatDate(d.getFullYear(), d.getMonth() + 1, d.getDate()));

            },
            mounted() {
                this.isApp()
            },
            methods: {
                initData: function (cur) {
                    this.days = []; //数据初始化
                    var date = new Date(cur);
                    this.currentDay = date.getDate();
                    this.currentYear = date.getFullYear();
                    this.currentMonth = date.getMonth() + 1;
                    this.currentWeek = date.getDay(); // 1...6,0
                    if (this.currentWeek == 0) this.currentWeek = 7; // 今天是周日,放在第一行第7个位置,前面6个
                    var thisMonthDays = new Date(this.currentYear, this.currentMonth, 0).getDate() //当月总天数
                    var thisMonthFirstDayIsWeeks = new Date(this.currentYear, this.currentMonth - 1, 1)
                        .getDay() == 0 ? 7 : new Date(this.currentYear, this.currentMonth - 1, 1)
                    .getDay() //当月第一天是周几,周日是0
                    var thisMonthLastDayIsWeeks = new Date(this.currentYear, this.currentMonth - 1,
                        thisMonthDays).getDay() == 0 ? 7 : new Date(this.currentYear, this
                        .currentMonth - 1, thisMonthDays).getDay() //当月最后一天是周几

                    // console.log("thisMonthDays:",thisMonthDays,";","thisMonthFirstDayIsWeeks:",thisMonthFirstDayIsWeeks,";","thisMonthLastDayIsWeeks:",thisMonthLastDayIsWeeks,";")
                    //上一个月
                    if (thisMonthFirstDayIsWeeks != 1) { //当月的第一天不是周一,需要补全前面的(上一个月的)天数
                        var y = this.currentMonth == 1 ? this.currentYear - 1 : this.currentYear
                        var m = this.currentMonth == 1 ? 12 : this.currentMonth - 1
                        var d = new Date(y, m, 0).getDate() //上一个月总天数
                        for (let i = 0; i < thisMonthFirstDayIsWeeks - 1; i++) { //判断上一个月是不是前一个年的最后一个月
                            var newD = new Date(y, m - 1, d - (thisMonthFirstDayIsWeeks - (i + 2)))
                            var dayobject = {};
                            dayobject.day = newD;
                            dayobject.isThisMonth = false
                            dayobject.isThisDay = false
                            this.days.push(dayobject);
                        }
                    }
                    //当前月
                    for (var i = 0; i < thisMonthDays; i++) {
                        var newD = new Date(this.currentYear, this.currentMonth - 1, i + 1)
                        var dayobject = {};
                        dayobject.day = newD;
                        dayobject.isThisMonth = true
                        dayobject.isThisDay = i + 1 == this.currentDay
                        this.days.push(dayobject);
                    }
                    //下一个月
                    if (thisMonthLastDayIsWeeks != 7) {
                        for (let i = 0; i < 7 - thisMonthLastDayIsWeeks; i++) { //判断下一个月是不是下一年的第一个月
                            var newD = new Date(this.currentMonth == 11 ? this.currentYear + 1 : this
                                .currentYear, this.currentMonth == 11 ? 0 : this.currentMonth, i + 1)
                            var dayobject = {};
                            dayobject.day = newD;
                            dayobject.isThisMonth = false
                            dayobject.isThisDay = false
                            this.days.push(dayobject);
                        }
                    }
                },
                pickPre: function (year, month) {
                    // setDate(0); 上月最后一天
                    // setDate(-1); 上月倒数第二天
                    // setDate(dx) 参数dx为 上月最后一天的前后dx天
                    if (month == 1) {
                        month = 12
                        year = year - 1
                    } else {
                        month = month - 1
                    }
                    this.initData(this.formatDate(year, month, 1));
                },
                pickNext: function (year, month) {
                    if (month == 12) {
                        month = 1
                        year = year + 1
                    } else {
                        month = month + 1
                    }
                    this.initData(this.formatDate(year, month, 1));
                },
                pickYear: function (year, month, type, e) {
                    var top = e.y + 32,
                        left = e.x - 120;
                    this.showMonth = false
                    this.showYearList = false
                    if (type == 1) {
                        this.yearList.length = 9
                        for (let i = 0; i < this.yearList.length; i++) {
                            if (i < 4) {
                                this.yearList[i] = year - (4 - i)
                            } else {
                                this.yearList[i] = year + (i - 4)
                            }
                        }
                        this.showYearList = true
                    } else {
                        this.showMonth = true
                        this.month = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
                    }
                    this.$nextTick(function () {
                        this.$refs.container.style = `top:${top}px;left:${left}px;`
                    })
                },
                // 返回 类似 2016-01-02 格式的字符串
                formatDate: function (year, month, day) {
                    var y = year;
                    var m = month;
                    if (m < 10) m = "0" + m;
                    var d = day;
                    if (d < 10) d = "0" + d;
                    var data = y + "-" + m + "-" + d
                    return data
                },
                changeDay(dayobject) {
                    const dayDetail = dayobject.day
                    return dayDetail
                },
                selectYear(item){
                    this.showYearList = false
                    this.currentYear = item
                    this.initData(this.formatDate(this.currentYear,this.currentMonth,this.currentDay))
                },
                selectMonth(item){
                    this.showMonth = false
                    this.currentMonth = item
                    this.initData(this.formatDate(this.currentYear,this.currentMonth,this.currentDay))
                },
                isApp() {
                    // console.log(window.navigator)
                    if (window.navigator.userAgent.includes("Mobile")) {
                        this.$refs.calendar.style.width = "90%"
                    }
                }
            },
        });

功能包括选择年份和月份
年份是当前年份前后各四个年份
因为这个是我日常写的东西没有在Vue项目中去使用,把这个迁移到Vue项目做为组件。
功能难点主要是当月的前一个月的日期和后一个月的日期的显示。在代码initDate()方法中实现
CSS方面使用grid布局和flex布局比较灵活。
仅供大家参考。
欢迎大家指点。

Logo

前往低代码交流专区

更多推荐