elementui 日历组件el-calendar使用总结

avatar
作者
猴君
阅读量:3

功能:

1.日历可以周视图、月视图切换;

2.点击月视图中日期可以切换到对应周视图;

3.点击周视图查看当日对应数据;

4.周、月视图状态下,点击前后按钮,分别切换对应上下的周、月;

5.点击回到今天,立即切回到周、月视图下对应的当日;

引用dayjs处理日期,结合el-calendar完美实现。

要注意的是,日历显示周的话,传的日期范围要按照计算所在星期,比如我们的需求是周日为每周起始日,那么就要给周日的日期和周六日期为起始日,月视图我不想再去计算日期范围了,就直接用了:value,注意用的不是v-model而是value,因为value是单向的,v-model是双向数据绑定了。

<template> <div class="childContainer">   <CompBar name="XX日历" iconName="rili.png" titleName="回到今天" @handleBarClick="nowCalendar">   <div class="kalendar">      <div class="kalendar-header">         <span class="current-monuth">             <i class="el-icon-caret-left" @click="showPrev"></i>             <i class="el-icon-caret-right" @click="showNext"></i>         </span>         <el-radio-group v-model="monthYear" size="mini">             <el-radio-button label="周"></el-radio-button>             <el-radio-button label="月"></el-radio-button>         </el-radio-group>     </div>     <CalendarMonth v-if="monthYear==='月'" :calendarValue="monthDate" :selectDay="dayDate" :dateList="dateList" @getPlanList="getplanList"></CalendarMonth>     <CalendarWeek v-else :rangeArr="dateRange" :selectDay="dayDate" :dateList="dateList"          @getPlanList="getplanList"></CalendarWeek>   </div>   <tabs :class="monthYear==='月'?'monthTabs':'weekTabs'" v-model="activePlan" v-loading="isLoading">     <el-tab-pane name="tabApplyEndPlan"> //此处是个列表 </el-tab-pane>     <el-tab-pane name="tabEndPlan"></el-tab-pane>   </tabs> </template> // 此处省略组件、接口引入 import dayjs from 'dayjs'; var weekplugin = require('dayjs/plugin/weekday'); dayjs.extend(weekplugin)  // 此处省略,直接放核心代码 data(){    return{     activePlan:'tabApplyEndPlan',     monthYear:'周', // 周、月视图切换,默认显示周     monthDate:'', // 传后端参数 YYYY-MM,查视图上需要显示点的日期     dayDate:'', // 传后端参数 YYYY-MM-DD,查视图下面对应的当日数据列表     dateRange:[], // 周日历,传入周日历视图日期范围     dateList:[], // 存放月数据,视图中需要显示点的日期    } },  watch:{ // 比较简单,直接省略代码了,记录下逻辑 // 监听 monthDate、dayDate 值的改变,调用对应接口 },  methods:{ showPrev() {         // 上个月         if (this.monthYear === '月') {           this.monthDate = dayjs(this.monthDate).add(-1, 'month').format('YYYY-MM');           // 需要判断当前选中日期是否属于当前月份           let _dayDate = dayjs(this.dayDate).format('YYYY-MM');           if (_dayDate === this.monthDate) {             // 计算本周第一天             let day1 = dayjs(this.dayDate).startOf('week').format('YYYY-MM-DD');             // 计算本周最后一天             let day2 = dayjs(this.dayDate).endOf('week').format('YYYY-MM-DD');             this.dateRange = [day1, day2];           } else {             let day1 = dayjs(this.monthDate).startOf('month').startOf('week').format('YYYY-MM-DD');             let day2 = dayjs(this.monthDate).startOf('month').endOf('week').format('YYYY-MM-DD');             this.dateRange = [day1, day2]           }         }         // 上星期         if (this.monthYear === '周') {           // 获取当前周视图           let day1 = dayjs(this.dateRange[0]).add(-1, 'week').startOf('week').format('YYYY-MM-DD');           let day2 = dayjs(this.dateRange[1]).add(-1, 'week').endOf('week').format('YYYY-MM-DD');           this.monthDate = dayjs(this.dateRange[0]).add(-1, 'week').startOf('week').format('YYYY-MM');           this.dateRange = [day1, day2]         }       },  showNext() {         // 下个月         if (this.monthYear === '月') {           this.monthDate = dayjs(this.monthDate).add(1, 'month').format('YYYY-MM');           // 需要判断当前选中日期是否属于当前月份           let _dayDate = dayjs(this.dayDate).format('YYYY-MM');           if (_dayDate === this.monthDate) {             // 计算本周第一天             let day1 = dayjs(this.dayDate).startOf('week').format('YYYY-MM-DD');             // 计算本周最后一天             let day2 = dayjs(this.dayDate).endOf('week').format('YYYY-MM-DD');             this.dateRange = [day1, day2];           } else {             let day1 = dayjs(this.monthDate).endOf('month').startOf('week').format('YYYY-MM-DD');             let day2 = dayjs(this.monthDate).endOf('month').endOf('week').format('YYYY-MM-DD');             this.dateRange = [day1, day2]           }         }         // 下星期         if (this.monthYear === '周') {           // 获取当前周视图           let day1 = dayjs(this.dateRange[0]).add(1, 'week').startOf('week').format('YYYY-MM-DD');           let day2 = dayjs(this.dateRange[1]).add(1, 'week').endOf('week').format('YYYY-MM-DD');           this.monthDate = dayjs(this.dateRange[0]).add(1, 'week').startOf('week').format('YYYY-MM');           this.dateRange = [day1, day2]         }       }, // 返回今日      nowCalendar() {       this.monthDate = dayjs(new Date()).format('YYYY-MM');       this.dayDate = dayjs(new Date()).format('YYYY-MM-DD');       let day1 = dayjs(new Date()).startOf('week').format('YYYY-MM-DD');       let day2 = dayjs(new Date()).endOf('week').format('YYYY-MM-DD');       this.dateRange = [day1, day2];       this.activePlan = 'tabApplyEndPlan'     }, // 周、月视图日期被点击处理方法     getPlanList(date) {       // console.log(this.monthYear)       // console.log(date)       this.dayDate = date.day;       // 点击上、下月/周日期,不涉及视图的切换       if (this.monthYear === '月') {         if (date.type === 'next-month') {           this.showNext()         }         if (date.type === 'prev-month') {           this.showPrev()         }       }       if (this.monthYear === '周') {         let _month = dayjs(date.day).format('YYYY-MM');         if (date.type === 'next-month') {           if (_month !== this.monthDate) {             this.monthDate = dayjs(date.day).format('YYYY-MM');           }         }         if (date.type === 'prev-month') {           if (_month !== this.monthDate) {             this.monthDate = dayjs(date.day).format('YYYY-MM');           }         }       }       if (date.type === 'current-month') {         this.monthYear = '周';         // 计算本周第一天         let day1 = dayjs(this.dayDate).startOf('week').format('YYYY-MM-DD');         // 计算本周最后一天         let day2 = dayjs(this.dayDate).endOf('week').format('YYYY-MM-DD');         // 计算点击日期所在周第一天所属月         this.monthDate = dayjs(day1).startOf('week').format('YYYY-MM');         this.dateRange = [day1, day2];       }     },  }   

自定义日历样式(没有用日历原先的头,全部自己重写的,还不错): 

::v-deep .kalendar {     &-header {       text-align: center;       margin: 10px 16px 0 16px;        .current-monuth {         font-size: 16px;         letter-spacing: 0;         font-weight: 500;         margin-left: 15%;         color: #262626;         font-family: PingFangSC-Medium;          i {           cursor: pointer;         }       }        .el-radio-group {         float: right;       }        .el-radio-button__orig-radio:checked + .el-radio-button__inner {         background: #ffffff;         box-shadow: -1px 0 0 0 transparent;         border: 1px solid rgba(199, 0, 11, 1);         font-family: PingFangSC-Medium;         font-size: 12px;         color: #c7000b;         letter-spacing: -0.04px;         font-weight: 500;       }        .el-radio-button__inner:hover {         color: #c7000b;       }     }      .calender-dot-box {       width: 100%;       bottom: -8px;       position: absolute;        span {         width: 6px;         height: 6px;         margin-right: 3px;         border-radius: 50%;         display: inline-block;          &:last-of-type {           margin-right: 0;         }       }        .endPlan {         background-color: #d61212;       }        .applyEndPlan {         background-color: #ffd100;       }     }      .el-calendar {       &__body {         padding: 10px 16px;       }        .is-today {         .el-calendar-day {           .calender-date {             width: 34px;             height: 34px;             margin: 0 auto;             color: #ff534f;             border-radius: 10px;             background: #fff;             box-shadow: none;           }         }       }        &__header {         display: none;       }        .current {         .el-calendar-day {           color: #262626;         }       }        .prev,       .next {         color: #bfbfbf;       }        &-day {         padding: 0;         font-weight: 700;         font-size: 16px;         letter-spacing: 0;         text-align: center;         position: relative;         transition: color 0.3s;         font-family: DINAlternate-Bold;       }        &-table {         th {           font-family: PingFangSC-Regular;           font-size: 16px;           color: #262626;           letter-spacing: 0;           text-align: center;           line-height: 34px;           font-weight: 400;           padding: 0;            &:last-of-type,           &:first-of-type {             color: #ff564e;           }         }          td {           border: none;            &.is-selected {             background-color: transparent;           }         }          .el-calendar-day {           height: 34px;           line-height: 34px;            &:hover {             background-color: transparent;           }            .calendar-isSelected {             width: 34px;             height: 34px;             margin: 0 auto;             color: #fff;             border-radius: 10px;             background: #ff534f;             box-shadow: 0px 0px 2px 0px rgba(238, 88, 64, 1);           }         }       }     }

再看看子组件里面,先看月的:

<template>   <!-- 月日历 -->   <el-calendar :value="calendarValue" :first-day-of-week="7" value-format="YYY-MM">     <template slot="dateCell" slot-scope="{ date, data }">       <div v-if="selectedDay === data.day" class="calendar-isSelected" @click="handleDate($event, date, data)">         {{ date.getDate() }}       </div>       <div v-else class="calender-date" @click="handleDate($event, date, data)">         {{ date.getDate() }}       </div>       <div class="calender-dot-box" @click="handleDate($event, date, data, 'dot')">         <template v-for="(item) in dateLists">           <span class="applyEndPlan" v-if="item.date === data.day && item.applyEndPlanNum > 0"></span>           <span class="endPlan" v-if="item.date === data.day && item.endPlanNum > 0"></span>         </template>       </div>     </template>   </el-calendar> </template> <script> export default {   components: {},   name: "CalendarMonth",   props: {     selectedDay: {       type: String,       default: "",     },     calendarValue: {       type: String,       default: new Date(),     },     dateList: {       type: Array,       default: () => {         return [];       },     },   },   watch: {     dateList: {       handler(list) {         this.dateLists = list;       },       immediate: true,     },   },   data() {     return { monthDate: this.calendarValue, dateLists: [] };   },   created() { },   methods: {     handleDate(e, date, data) {       this.$emit("getPlanList", data);     },   }, }; </script> <style lang="scss" scoped></style>

周日历组件:

<template>   <!-- 周日历 -->   <el-calendar :range="rangeArr" :first-day-of-week="7" value-format="YYY-MM">     <template slot="dateCell" slot-scope="{date,data}">       <div v-if="selectedDay === data.day" class="calendar-isSelected" @click="handleDate($event, date, data)">         {{ date.getDate() }}</div>        <div v-else class="calender-date" @click="handleDate($event, date, data)">{{ date.getDate() }}</div>       <div class="calender-dot-box" @click="handleDate($event, date, data)">         <template v-for="(item) in dateList">           <span class="applyEndPlan" v-if="item.date === data.day && item.applyEndPlanNum > 0"></span>           <span class="endPlan" v-if="item.date === data.day && item.endPlanNum > 0"></span>         </template>       </div>     </template>   </el-calendar> </template> <script> export default {   components: {}, name: 'CalendarWeek', props: {     selectedDay: {       type: String, default: '',     }, rangeArr: {       type: Array,       default: () => {         return [];       }     }, dateList: {       type: Array, default: () => {         return [];       }     }   }, data() {     return {     }   }, created() {   }, methods: {     handleDate(e, date, data) {       // console.log(e,date,data)       this.$emit('getPlanList', data)     },   } }</script> <style lang="scss" scoped></style>

其实应该把日历组件二次封装一下,就不用单独再去写周、月日历子组件了,有空了可以试试。

不过不得不再吐槽一句,elementui的日历组件,给提供的API真心的少,功能很简单。。。

最终效果图:

月视图效果图:

月视图下,有时候会出现整整一行的灰色日期,看起来不是很美观,那么就需要操作dom,通过js判断,操作dom来处理。大概思路就是,先通过 document.querySelectorAll('.el-calendar-table__row') 获取到所有.el-calendar-table__row的元素节点lists,然后循环遍历这些节点,若其子元素class中含有.current,那么就说明是带有当月的日期,则不改变样式,若不含,则说明这整行都是前\后月的日期,那么就可以把该.el-calendar-table__row的css里面加上属性display:none。

周视图效果图: 

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!