- 作者:老汪软件技巧
- 发表时间:2024-10-08 04:00
- 浏览量:
简单的酒店日程日历展示
在本篇博客中,我将分享如何使用 Vue 3、 Element Plus、 date-fns 创建一个动态日历组件,该组件支持房间预订管理功能。这个组件不仅美观,而且用户友好,能够直观地展示每个房间在不同日期的可用性和预订情况。
项目简览概述
我们构建的这个日历组件具有以下功能:
概览
初始化展示当天所在月的预定情况
可选定日期进行跳转 并高亮与居中选中日期
可以通过按钮跳转上个月与下个月 来查看预定信息
点击预定信息已预定的房间 可切换为可用 再次点击输入用户信息来进行预定
组件结构模板部分
在组件的模板中,我们使用了 Element Plus 的表格组件 (el-table) 来展示房间信息和预订状态。下面是组件的核心结构:
class="calendar">
class="controls">
click="previousMonth">上个月
v-model="selectedDate"
type="date"
format="YYYY-MM-DD"
placeholder="选择日期"
@change="handleDateChange"
/>
click="nextMonth">下个月
ref="tableRef"
:data="tableData"
stripe
border
style="width: 100%"
:cell-style="columnStyle"
:header-cell-style="columnStyle"
>
label="房间类型"
prop="roomType"
width="150"
align="center"
>
v-for="(day, index) in days"
:key="index"
align="center"
:label="day.label"
:prop="day.prop"
:width="150"
>
#default="scope">
v-if="isEditing(scope.row, day.prop)" class="editing-cell">
v-model="scope.row[day.prop].customerName"
placeholder="输入用户名"
@blur="saveBooking(scope.row, day.prop)"
@keyup.enter="saveBooking(scope.row, day.prop)"
/>
class="['cell-content', { 'non-clickable': scope.row.roomType === '剩几间房' }]"
@click="handleCellClick(scope.row, day.prop)"
>
v-if="scope.row.roomType === '剩几间房'">
{{ scope.row[day.prop] }}
v-else-if="isBooked(scope.row, day.prop)">
已预订
{{ scope.row[day.prop].customerName }}
可用
状态管理
我们使用了 Vue 的响应式特性来管理组件状态,包括选定的日期、当前月份的开始日期、天数和表格数据。以下是部分状态定义代码:
const selectedDate = ref(new Date());
const currentMonthStartDate = ref(startOfMonth(selectedDate.value));
const days = ref([]);
const tableData = ref([]);
生成月份天数
通过 generateMonthDays 函数,我们动态生成当前月份的天数,并为每一天设置标签和属性:
const generateMonthDays = () => {
const daysArray = [];
const start = startOfMonth(currentMonthStartDate.value);
const daysInMonth = getDaysInMonth(start);
for (let i = 0; i < daysInMonth; i++) {
const date = addDays(start, i);
daysArray.push({
label: format(date, 'dd\nEEE', {locale: zhCN}),
prop: `day${i + 1}`
});
}
return daysArray;
};
更新表格数据
表格数据的更新通过 updateTableData 函数来实现,我们根据选定的月份和房间的预订状态来填充表格数据:
const updateTableData = () => {
// ...更新逻辑
const roomData = Array.from({length: 5}, (_, rowIndex) => {
const row = {roomType: `房间${rowIndex + 1}`};
// 随机生成房间状态
return row;
});
// 添加剩余房间数的行
const availableRoomsRow = {roomType: '剩几间房'};
// ...计算剩余房间数
tableData.value = [availableRoomsRow, ...roomData];
};
处理用户交互
我们通过事件处理函数如handleCellClick和saveBooking来处理用户的点击和保存操作。这些函数确保用户能够轻松地输入预订信息,并实时更新房间的状态。
// 处理单元格点击事件
const handleCellClick = (row, prop) => {
if (row.roomType === '剩几间房') return;
if (row[prop].status === '可用') {
editingCell.value = {rowProp: row.roomType, dayProp: prop};
row[prop].customerName = '';
} else {
row[prop] = {status: '可用', customerName: ''};
updateAvailableRooms(prop);
}
};
// 保存预订信息
const saveBooking = (row, prop) => {
const customerName = row[prop].customerName.trim();
if (customerName !== '') {
row[prop].status = '已预订';
} else {
row[prop].status = '可用';
}
editingCell.value = {rowProp: null, dayProp: null};
updateAvailableRooms(prop);
};
优化用户体验
通过scrollToSelectedDate和columnStyle来处理选定日期居中和高亮
const scrollToSelectedDate = (date) => {
const selectedDay = format(date, 'dd');
const columnIndex = parseInt(selectedDay) - 1; // 获取列索引,假设日期为 01 - 31 对应索引 0 - 30
const columnWidth = 150; // 根据你的列宽设置
const tableWidth = tableRef.value.$el.offsetWidth;
// 计算居中位置
const scrollLeft = (columnIndex + 1) * columnWidth - (tableWidth / 2) + (columnWidth / 2);
// 调用 setScrollLeft 滚动到对应列
if (tableRef.value) {
tableRef.value.setScrollLeft(scrollLeft);
}
};
const columnStyle = ({row, column}) => {
const dayProp = column.property;
if (selectedDate.value && isCurrentDay(dayProp)) {
return {backgroundColor: '#1C86EE', color: '#fff'}; // 高亮的样式
}
return {};
};
样式
我们为组件添加了一些基本样式,使其更加美观和易于使用:
.calendar {
max-width: 100%;
margin: 0 auto;
}
.controls {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.cell-content {
cursor: pointer;
white-space: pre-line;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
完整的代码
class="calendar">
class="controls">
click="previousMonth">上个月
v-model="selectedDate"
type="date"
format="YYYY-MM-DD"
placeholder="选择日期"
@change="handleDateChange"
/>
click="nextMonth">下个月
ref="tableRef"
:data="tableData"
stripe
border
style="width: 100%"
:cell-style="columnStyle"
:header-cell-style="columnStyle"
>
label=""
prop="roomType"
width="150"
align="center"
>
v-for="(day, index) in days"
:key="index"
align="center"
:label="day.label"
:prop="day.prop"
:width="150"
v-memo="[day, tableData]"
>
#default="scope">
v-if="isEditing(scope.row, day.prop)" class="editing-cell">
v-model="scope.row[day.prop].customerName"
placeholder="输入用户名"
@blur="saveBooking(scope.row, day.prop)"
@keyup.enter="saveBooking(scope.row, day.prop)"
/>
class="['cell-content', { 'non-clickable': scope.row.roomType === '剩几间房' }]"
@click="handleCellClick(scope.row, day.prop)"
>
v-if="scope.row.roomType === '剩几间房'">
{{ scope.row[day.prop] }}
v-else-if="isBooked(scope.row, day.prop)">
已预订
{{ scope.row[day.prop].customerName }}
可用
总结
通过本次分享,我们学习了如何使用 Vue 3 和 Element Plus 创建一个功能完备的动态日历组件。这个组件展示了 Vue 的响应式能力和 Element Plus 组件库的强大功能,能够高效地处理房间预订的需求。希望这篇博客能对你的项目开发有所帮助!