vue简单日历实现

需求:日历以面板形式展示,且以小红点表示当天有任务

<div class="calendar">
    <div class="calendar-title">
        <b class="b">日程安排</b>
        <el-date-picker
            v-model="times"
            size="mini"
            type="month"
            :clearable="false"
            style="width: 120px"
            @change="handleChange">
        </el-date-picker>
    </div>
    <div class="mg-evt-calendar-body">
        <div class="calendar-head">
            <div class="calendar-head-item" v-for="(item, index) in weeksList" :key="index">
                {{ item.label }}
            </div>
        </div>
        <div class="calendar-body">
            <div class="calendar-module" v-for="(item, index) in daysList" :key="index">
                <div
                    class="calendar-module-item"
                    v-for="(_item, _index) in item"
                    :key="_index"
                    :class="[
                        _item.date && _item.date === currentDate ? 'active' : '',
                        setDateClass(_item.date),
                        setDateBadge(_item.date)
                    ]"
                    @click="handleClickDay(_item.date)"
                >
                    <span>{{ _item.date ? formatCalendarDay(_item.date) : "" }}</span>
                </div>
            </div>
        </div>
    </div>
</div>

html部分代码如上,setDateClass设置当天日期样式,setDateBadge给有任务的日期设置样式,handleClickDay为日期点击事件可获取当前点击日期

下面是js部分,时间插件用的是dayjs

data() {
    return {
        // 右侧日历相关
        weeksList: [
            { label: "日", value: 0, fullName: "星期日" },
            { label: "一", value: 1, fullName: "星期一" },
            { label: "二", value: 2, fullName: "星期二" },
            { label: "三", value: 3, fullName: "星期三" },
            { label: "四", value: 4, fullName: "星期四" },
            { label: "五", value: 5, fullName: "星期五" },
            { label: "六", value: 6, fullName: "星期六" },
        ],
        daysList: [],
        year: "",
        month: "",
        times: new Date(),
        renderDateList: [],
        currentDate: "",
    }
},
methods: {
    // 切换月份
    handleChange(time) {
        if(time) {
            this.year = dayjs(time).format("YYYY");
            this.month = dayjs(time).format("MM");
            this.setDaysData();
            this.renderDateList = [];
            this.query.startTime = dayjs(time).startOf("month").startOf("day").toISOString();
            this.query.endTime = dayjs(time).endOf("month").endOf("day").toISOString();
        }
    },
    // 设置某月每天数据
    setDaysData() {
        let days = new Date(this.year, this.month, 0).getDate();    //获取某月的总天数
        let daysList = Array.from({length: days}).map((_, index) => {
            let _index = index > 8 ? index + 1 : `0${index+1}`;
            let day = `${this.year}-${this.month}-${_index}`;
            return {
                date: day,
                weekValue: new Date(day).getDay(),  //获取某天对应的星期几
            }
        });
        // 获取某月第一天对应的星期几
        let currentIndex = this.weeksList.findIndex(item => item.value == daysList[0].weekValue);
        // 往总天数中添加currentIndex个对象用于错位
        let addList = Array.from({length: currentIndex}).map((_, index) => {
            return {
                date: "",
                weekValue: ""
            }
        });
        // 合并
        let mergeArr = [...addList, ...daysList];
        let resultList = [];
        let index = 0;
        // 将数组分为长度为7的数组方便页面循环
        while(index < days) {
            resultList.push(mergeArr.slice(index, index += 7));
        }
        this.daysList = resultList;
    },
    // 格式化日历中的日期
    formatCalendarDay(date) {
        return dayjs(date).format("D");
    },
    // 设置当天日期样式
    setDateClass(date) {
        if(date) {
            return dayjs().format("YYYY-MM-DD") === date ? "current" : "";
        }
    },
    // 设置日期小红点
    setDateBadge(date) {
        if(date) {
            return this.renderDateList.includes(date) ? "badge" : "";
        }
    },
    // 日历点击事件
    handleClickDay(date) {
        if(date) {
        	// 设置选中样式
            if(this.currentDate !== date) {
                this.currentDate = date;
            }else{
            	// 去除选中样式
                this.currentDate = "";
            }
        }
    },
    // 渲染日历时间
    renderDates(times) {
        this.renderDateList = times;
    },
}

下面是相关样式

.calendar{
    width: 580px;
    background: #fff;
    .calendar-head{
        display: flex;
        margin-bottom: 10px;
        .calendar-head-item{
            display: flex;
            width: calc((100% - 6px) / 7);
            height: 30px;
            color: #fff;
            line-height: 1;
            align-items: center;
            justify-content: center;
            background-color: #4B7EFE;
            &:not(:last-child) {
                margin-right: 1px;
            }
        }
    }
    .calendar-body{
        .calendar-module{
            display: flex;
            margin-bottom: 10px;
        }
        .calendar-module-item{
            display: flex;
            position: relative;
            width: calc((100% - 6px) / 7);
            height: 35px;
            line-height: 35px;
            text-align: center;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            &:not(:last-child) {
                margin-right: 1px;
            }
            span{
                position: relative;
                display: block;
                width: 25px;
                height: 25px;
                line-height: 25px;
            }
            &.current{
                span{
                    border-radius: 100%;
                    border: 1px solid #4B7EFE;
                }
            }
            &.active{
                border-bottom: none;
                span{
                    color: #fff;
                    border-radius: 100%;
                    background-color: #4B7EFE;
                }
            }
            &.badge{
                span::after{
                    position: absolute;
                    top: -4px;
                    right: -4px;
                    width: 8px;
                    height: 8px;
                    border-radius: 100%;
                    background-color: red;
                    content: "";
                }
            }
        }
    }
}

最终的效果图如下:

在这里插入图片描述

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单Vue3 日历组件的实现示例: ```html <template> <div> <div class="calendar-header"> <button @click="prevMonth">上个月</button> <h3>{{ monthStr }}</h3> <button @click="nextMonth">下个月</button> </div> <div class="calendar-grid"> <div v-for="(day, index) in days" :key="index" :class="{ 'calendar-cell': true, 'calendar-cell-disabled': !day }"> {{ day }} </div> </div> </div> </template> <script> import { computed, reactive } from 'vue' export default { setup() { const state = reactive({ currentMonth: new Date(), days: [] }) const prevMonth = () => { state.currentMonth.setMonth(state.currentMonth.getMonth() - 1) } const nextMonth = () => { state.currentMonth.setMonth(state.currentMonth.getMonth() + 1) } const monthStr = computed(() => { return state.currentMonth.toLocaleString('default', { month: 'long', year: 'numeric' }) }) const generateCalendar = () => { const firstDay = new Date(state.currentMonth.getFullYear(), state.currentMonth.getMonth(), 1).getDay() const lastDay = new Date(state.currentMonth.getFullYear(), state.currentMonth.getMonth() + 1, 0).getDate() const days = new Array(35).fill(null) for (let i = 1; i <= lastDay; i++) { days[firstDay + i - 1] = i } state.days = days } generateCalendar() return { state, prevMonth, nextMonth, monthStr } } } </script> <style> .calendar-grid { display: grid; grid-template-columns: repeat(7, 1fr); } .calendar-cell { border: 1px solid #ccc; padding: 10px; text-align: center; } .calendar-cell-disabled { opacity: 0.3; } </style> ``` 这个组件使用了 Vue3 的 `reactive` 和 `computed` 函数来声明响应式状态和计算属性。它还使用了 JavaScript 的 `Date` 对象来计算日历表格中的日期。在 `setup` 函数中,我们定义了一些帮助函数来生成日历,并将它们绑定到组件的方法中。最后,我们通过使用 CSS Grid 布局来组织日历表格的每个单元格。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值