VUE3组件综合应用(日历组件)

了解组件基础概念:学习组件的定义、注册和使用方式。

组件间数据传递:完善并实现课本日历综合案例,要求使用vue3语法,按照组件应用方法编写程序。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue 3 日历组件</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            margin: 0;
            background-color: #f5f5f5;
        }

        .calendar-container {
            width: 350px;
            background: white;
            border: 1px solid #ddd;
            border-radius: 8px;
            overflow: hidden;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
        }
        .calendar-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 10px;
            background-color: #f5f5f5;
            border-bottom: 1px solid #ddd;
        }
        .calendar-header button {
            background: none;
            border: 1px solid #ddd;
            border-radius: 4px;
            padding: 5px 10px;
            cursor: pointer;
            transition: background-color 0.2s;
        }
        .calendar-header button:hover {
            background-color: #e0e0e0;
        }
        .calendar-weekdays {
            display: grid;
            grid-template-columns: repeat(7, 1fr);
            background-color: #f9f9f9;
            padding: 8px 0;
            text-align: center;
            font-weight: bold;
        }        
        .calendar-days {
            display: grid;
            grid-template-columns: repeat(7, 1fr);
            gap: 4px;
            padding: 8px;
        }        
        .day {
            height: 40px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 4px;
            cursor: pointer;
            transition: all 0.2s;
        }        
        .day:hover {
            background-color: #f0f0f0;
        }      
        .current-month {
            background-color: white;
        }
        .day:not(.current-month) {
            color: #aaa;
        }
        .selected {
            background-color: #4285f4;
            color: white;
        }
        .selected:hover {
            background-color: #3367d6;
        }
        .today {
            font-weight: bold;
            border: 1px solid #4285f4;
        }
        .selected.today {
            border-color: white;
        }
        .selected-day {
            margin-top: 20px;
            text-align: center;
            font-size: 1.2em;
        }
    </style>
</head>
<body>
    <div id="app">
        <calendar v-model="selectedDate"></calendar>
        <div class="selected-day" v-if="selectedDate">
            已选择: {{ formatDate(selectedDate) }}
        </div>
    </div>

    <script>
        const { createApp, ref, computed } = Vue;
        
        const Calendar = {
            template: `
                <div class="calendar-container">
                    <div class="calendar-header">
                        <button @click="prevMonth">&lt;</button>
                        <h2>{{ currentMonthYear }}</h2>
                        <button @click="nextMonth">&gt;</button>
                    </div>
                    
                    <div class="calendar-weekdays">
                        <div v-for="day in weekdays" :key="day" class="weekday">{{ day }}</div>
                    </div>
                    
                    <div class="calendar-days">
                        <div 
                            v-for="(day, index) in days" 
                            :key="index"
                            :class="{
                                'day': true,
                                'current-month': day.isCurrentMonth,
                                'selected': isSelected(day.date),
                                'today': isToday(day.date)
                            }"
                            @click="selectDate(day)"
                        >
                            {{ day.date.getDate() }}
                        </div>
                    </div>
                </div>
            `,
            props: {
                modelValue: {
                    type: Date,
                    default: null
                }
            },
            emits: ['update:modelValue'],
            setup(props, { emit }) {
                const currentDate = ref(new Date());
                const selectedDate = ref(props.modelValue ? new Date(props.modelValue) : null);
                
                const weekdays = ['日', '一', '二', '三', '四', '五', '六'];
                
                const currentMonthYear = computed(() => {
                    return `${currentDate.value.getFullYear()}年${currentDate.value.getMonth() + 1}月`;
                });
                
                const days = computed(() => {
                    const year = currentDate.value.getFullYear();
                    const month = currentDate.value.getMonth();
                    
                    // 当月第一天
                    const firstDay = new Date(year, month, 1);
                    // 当月最后一天
                    const lastDay = new Date(year, month + 1, 0);
                    // 上个月最后几天
                    const prevLastDay = new Date(year, month, 0);
                    // 下个月前几天
                    const nextFirstDay = new Date(year, month + 1, 1);
                    
                    const days = [];
                    
                    // 添加上个月的最后几天
                    const prevDays = firstDay.getDay();
                    for (let i = prevDays > 0 ? prevDays - 1 : 6; i >= 0; i--) {
                        days.push({
                            date: new Date(year, month - 1, prevLastDay.getDate() - i),
                            isCurrentMonth: false
                        });
                    }
                    
                    // 添加当月的所有天
                    for (let i = 1; i <= lastDay.getDate(); i++) {
                        days.push({
                            date: new Date(year, month, i),
                            isCurrentMonth: true
                        });
                    }
                    
                    // 添加下个月的前几天
                    const nextDays = 7 - lastDay.getDay() - 1;
                    for (let i = 1; i <= nextDays; i++) {
                        days.push({
                            date: new Date(year, month + 1, i),
                            isCurrentMonth: false
                        });
                    }
                    
                    // 确保总是显示6行(42天)
                    while (days.length < 42) {
                        const lastDate = days[days.length - 1].date;
                        days.push({
                            date: new Date(lastDate.getFullYear(), lastDate.getMonth(), lastDate.getDate() + 1),
                            isCurrentMonth: false
                        });
                    }
                    
                    return days;
                });
                
                const prevMonth = () => {
                    currentDate.value = new Date(
                        currentDate.value.getFullYear(),
                        currentDate.value.getMonth() - 1,
                        1
                    );
                };
                
                const nextMonth = () => {
                    currentDate.value = new Date(
                        currentDate.value.getFullYear(),
                        currentDate.value.getMonth() + 1,
                        1
                    );
                };
                
                const selectDate = (day) => {
                    if (day.isCurrentMonth) {
                        selectedDate.value = new Date(day.date);
                        emit('update:modelValue', selectedDate.value);
                    }
                };
                
                const isSelected = (date) => {
                    if (!selectedDate.value) return false;
                    return (
                        date.getDate() === selectedDate.value.getDate() &&
                        date.getMonth() === selectedDate.value.getMonth() &&
                        date.getFullYear() === selectedDate.value.getFullYear()
                    );
                };
                
                const isToday = (date) => {
                    const today = new Date();
                    return (
                        date.getDate() === today.getDate() &&
                        date.getMonth() === today.getMonth() &&
                        date.getFullYear() === today.getFullYear()
                    );
                };
                
                return {
                    currentDate,
                    selectedDate,
                    weekdays,
                    currentMonthYear,
                    days,
                    prevMonth,
                    nextMonth,
                    selectDate,
                    isSelected,
                    isToday
                };
            }
        };




        const app = createApp({
            components: {
                Calendar
            },
            setup() {
                const selectedDate = ref(null);
                
                const formatDate = (date) => {
                    return date.toLocaleDateString('zh-CN', {
                        year: 'numeric',
                        month: 'long',
                        day: 'numeric',
                        weekday: 'long'
                    });
                };
                
                return {
                    selectedDate,
                    formatDate
                };
            }
        });

        // app.component('Calendar', Calendar);
        app.mount('#app');
    </script>
</body>
</html>

运行结果如图:

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值