了解组件基础概念:学习组件的定义、注册和使用方式。
组件间数据传递:完善并实现课本日历综合案例,要求使用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"><</button>
<h2>{{ currentMonthYear }}</h2>
<button @click="nextMonth">></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>
运行结果如图: