vue3+element Plus中使用日期格式化库day.js

文章介绍了如何在Element-plus组件库中利用内置的day.js库进行日期时间处理,无需额外引入day.js,并提供了isSameOrBefore和isSameOrAfter扩展插件的使用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

element Plus中使用日期格式化库day.js,无需再单独引入day.js

Element-plus (opens new window)组件库默认支持 dayjs 进行日期时间处理,所以可以直接导入使用,相关 Date Picker (opens new window)组件介绍。

day.js官网链接dayjs.fenxianglu.cn/

Element-plus

示例:

javascript复制代码import { dayjs } from 'element-plus'

// 扩展插件
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'
dayjs.extend(isSameOrBefore)
dayjs.extend(isSameOrAfter)

dayjs().isSameOrBefore(dayjs('2011-01-01'))
<think>我们需要展示一个包含当前月份及前一个月份的日期表(例如当前是7月,则显示6月和7月)。我们可以使用Element Plus的日历组件(`el-calendar`)或者自己构建一个简单的月份视图。但是,由于需要展示两个月份,并且可能要求以表格形式展示,我们可以考虑使用两个`el-calendar`并排,或者自己构建一个自定义的月份表格。 由于`el-calendar`默认一次只显示一个月,所以我们可以使用两个`el-calendar`组件来分别显示上个月和当前月。 但是,根据需求,我们只需要展示两个月的日期,并且可能希望以更紧凑的方式(比如去掉不需要的头部和尾部),我们可以自己构建一个简单的月份表格。 这里我选择自己构建,因为这样更灵活,可以控制样式和布局。 思路: 1. 获取当前月份和上一个月份的信息(包括每个月的第一天是星期几,每个月的总天数)。 2. 构建两个数组,分别表示两个月的日期(包括上个月在本月显示的部分和下个月在本月显示的部分,类似于日历的完整视图)。 3. 使用表格展示这两个月,每个月份用一个表格表示,并排显示。 步骤: - 计算当前月份和上一个月的日期数据。 - 构建两个月的日历数组(长度为42,因为一个月最多6周,7天*6=42格)。 - 使用两个表格分别渲染这两个月的日历。 注意:我们要求只显示公历日期,不需要农历。 代码实现: 我们将创建一个组件,使用两个表格展示两个月的日历。 由于需要展示月份的名称,我们在表格上方显示月份标题。 我们将使用Vue3的Composition API。 下面是具体代码:</think># 月份日期表组件 - 展示当前月及前一个月的日期 下面是一个完整的Vue + Element Plus实现,用于展示当前月份及前一个月的日期表: ```vue <template> <div class="month-calendar-container"> <el-card class="calendar-card"> <div class="header"> <h1>月份日期表</h1> <p>展示当前月份及前一个月的日期</p> </div> <div class="calendar-controls"> <el-button @click="prevMonths" icon="el-icon-arrow-left" circle></el-button> <el-button type="primary" @click="resetToCurrent" plain>返回当前月份</el-button> <el-button @click="nextMonths" icon="el-icon-arrow-right" circle></el-button> </div> <div class="month-display"> <div class="month-title"> {{ formatMonth(prevMonth) }} </div> <div class="month-title"> {{ formatMonth(currentMonth) }} </div> </div> <div class="calendar-grid"> <!-- 前一个月 --> <div class="month-container"> <div class="weekdays"> <div v-for="day in weekDays" :key="day" class="weekday">{{ day }}</div> </div> <div class="days-grid"> <div v-for="(day, index) in prevMonthDays" :key="&#39;prev-&#39; + index" :class="[ &#39;day-cell&#39;, { &#39;current-month&#39;: day.isCurrentMonth, &#39;today&#39;: day.isToday, &#39;weekend&#39;: day.isWeekend } ]" > <div class="day-number">{{ day.day }}</div> <div v-if="day.isToday" class="today-badge">今天</div> <div v-if="day.events.length" class="events-indicator"> <el-badge :value="day.events.length" type="primary" /> </div> </div> </div> </div> <!-- 当前月 --> <div class="month-container"> <div class="weekdays"> <div v-for="day in weekDays" :key="day" class="weekday">{{ day }}</div> </div> <div class="days-grid"> <div v-for="(day, index) in currentMonthDays" :key="&#39;current-&#39; + index" :class="[ &#39;day-cell&#39;, { &#39;current-month&#39;: day.isCurrentMonth, &#39;today&#39;: day.isToday, &#39;weekend&#39;: day.isWeekend } ]" > <div class="day-number">{{ day.day }}</div> <div v-if="day.isToday" class="today-badge">今天</div> <div v-if="day.events.length" class="events-indicator"> <el-badge :value="day.events.length" type="primary" /> </div> </div> </div> </div> </div> <div class="legend"> <div class="legend-item"> <div class="color-box today"></div> <span>今天</span> </div> <div class="legend-item"> <div class="color-box weekend"></div> <span>周末</span> </div> <div class="legend-item"> <div class="color-box event"></div> <span>有事件</span> </div> </div> </el-card> </div> </template> <script> import { ref, computed, onMounted } from &#39;vue&#39;; import { format, startOfMonth, endOfMonth, eachDayOfInterval, addMonths, subMonths, isSameDay, isToday, isWeekend } from &#39;date-fns&#39;; import { zhCN } from &#39;date-fns/locale&#39;; export default { setup() { const currentDate = ref(new Date()); const weekDays = ref([&#39;日&#39;, &#39;一&#39;, &#39;二&#39;, &#39;三&#39;, &#39;四&#39;, &#39;五&#39;, &#39;六&#39;]); // 计算前一个月和当前月的日期范围 const prevMonth = computed(() => subMonths(currentDate.value, 1)); const currentMonth = computed(() => currentDate.value); // 格式化月份显示 const formatMonth = (date) => { return format(date, &#39;yyyy年MM月&#39;, { locale: zhCN }); }; // 生成日期数据 const generateMonthDays = (month) => { const start = startOfMonth(month); const end = endOfMonth(month); const days = eachDayOfInterval({ start, end }); // 计算日历中需要显示的前置天数(上个月的最后几天) const firstDayOfWeek = start.getDay(); const prevDays = []; for (let i = 0; i < firstDayOfWeek; i++) { const prevDate = new Date(start); prevDate.setDate(start.getDate() - (firstDayOfWeek - i)); prevDays.push({ day: prevDate.getDate(), date: prevDate, isCurrentMonth: false, isToday: isToday(prevDate), isWeekend: isWeekend(prevDate), events: [] }); } // 当前月的日期 const currentDays = days.map(day => ({ day: day.getDate(), date: day, isCurrentMonth: true, isToday: isToday(day), isWeekend: isWeekend(day), events: generateRandomEvents(day) })); // 组合所有日期 return [...prevDays, ...currentDays]; }; // 生成随机事件 const generateRandomEvents = (date) => { const events = []; // 30%的几率生成事件 if (Math.random() > 0.7) { const count = Math.floor(Math.random() * 3) + 1; for (let i = 0; i < count; i++) { events.push({ id: `${date.getTime()}-${i}`, title: `事件 ${i+1}`, time: `${Math.floor(Math.random() * 24)}:00` }); } } return events; }; // 计算前一个月和当前月的日期数据 const prevMonthDays = computed(() => generateMonthDays(prevMonth.value)); const currentMonthDays = computed(() => generateMonthDays(currentMonth.value)); // 导航功能 const prevMonths = () => { currentDate.value = subMonths(currentDate.value, 1); }; const nextMonths = () => { currentDate.value = addMonths(currentDate.value, 1); }; const resetToCurrent = () => { currentDate.value = new Date(); }; return { weekDays, prevMonth, currentMonth, prevMonthDays, currentMonthDays, formatMonth, prevMonths, nextMonths, resetToCurrent }; } }; </script> <style scoped> .month-calendar-container { max-width: 1200px; margin: 0 auto; padding: 20px; font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif; } .header { text-align: center; margin-bottom: 20px; } .header h1 { color: #2c3e50; margin-bottom: 8px; } .header p { color: #7f8c8d; font-size: 16px; } .calendar-card { border-radius: 12px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); padding: 25px; } .calendar-controls { display: flex; justify-content: center; align-items: center; gap: 20px; margin-bottom: 30px; } .calendar-controls .el-button { transition: all 0.3s ease; } .calendar-controls .el-button:hover { transform: scale(1.05); } .month-display { display: flex; justify-content: space-between; margin-bottom: 20px; padding: 0 10px; } .month-title { flex: 1; text-align: center; font-size: 20px; font-weight: bold; color: #3498db; background: linear-gradient(to right, #f8f9fa, #e9ecef); padding: 12px 0; border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); } .month-title:first-child { margin-right: 10px; } .month-title:last-child { margin-left: 10px; } .calendar-grid { display: flex; gap: 30px; } .month-container { flex: 1; border: 1px solid #e0e0e0; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05); background: white; } .weekdays { display: grid; grid-template-columns: repeat(7, 1fr); background-color: #f5f7fa; border-bottom: 1px solid #e0e0e0; } .weekday { padding: 12px 0; text-align: center; font-weight: bold; color: #5a6268; } .days-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px; background-color: #e0e0e0; } .day-cell { min-height: 100px; background-color: white; padding: 8px; position: relative; transition: all 0.2s ease; display: flex; flex-direction: column; } .day-cell:hover { background-color: #f8f9fa; transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05); z-index: 1; } .day-number { font-size: 16px; font-weight: 500; color: #2c3e50; align-self: flex-end; } .current-month .day-number { color: #2c3e50; } .day-cell:not(.current-month) .day-number { color: #bdc3c7; } .today { background-color: #e3f2fd; border: 2px solid #2196f3; } .today-badge { position: absolute; top: 5px; right: 5px; background-color: #2196f3; color: white; font-size: 10px; padding: 2px 6px; border-radius: 10px; } .weekend { background-color: #fff8e1; } .events-indicator { margin-top: auto; text-align: center; } .legend { display: flex; justify-content: center; gap: 25px; margin-top: 25px; padding-top: 15px; border-top: 1px solid #eee; } .legend-item { display: flex; align-items: center; gap: 8px; } .color-box { width: 20px; height: 20px; border-radius: 4px; } .color-box.today { background-color: #e3f2fd; border: 1px solid #2196f3; } .color-box.weekend { background-color: #fff8e1; border: 1px solid #ffc107; } .color-box.event { background-color: #e3f2fd; position: relative; } .color-box.event::after { content: ""; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 8px; height: 8px; background-color: #2196f3; border-radius: 50%; } </style> ``` ## 功能说明 这个组件实现了以下功能: 1. **双月展示**:同时展示当前月份和前一个月份的日历 2. **日期高亮**: - 当前日期(今天)使用特殊样式标识 - 周末日期使用不同背景色 - 当前月份日期使用正常颜色,非当前月份日期使用灰色 3. **事件指示**:有事件的日期会显示事件数量标记 4. **导航功能**: - 左右箭头按钮可向前/向后浏览月份 - "返回当前月份"按钮可快速回到当前月份 5. **响应式设计**:适配不同屏幕尺寸 6. **视觉设计**: - 使用卡片布局提升视觉层次 - 添加阴影和过渡效果增强用户体验 - 清晰的月份标题和日期标识 - 底部的图例说明 ## 实现原理 1. **日期处理**:使用 `date-fns` 进行日期计算和格式化 2. **日历生成**: - 计算每个月的第一天和最后一天 - 生成包含前置天数(上个月的最后几天)的完整日历网格 - 为每个日期添加附加信息(是否当前月、是否今天、是否周末) 3. **事件模拟**:随机生成事件数据用于演示 4. **响应式数据**:使用 Vue 的 computed 属性确保日期数据动态更新 5. **导航功能**:通过 `addMonths` 和 `subMonths` 实现月份切换
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值