当前位置: 首页 > news >正文

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

功能:

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。

周视图效果图: 

相关文章:

  • GESP C++ 三级真题(2023年9月)T1 ⼩ 杨储蓄
  • Ceph资源池pool管理
  • 常用图像分类、目标检测模型性能测试
  • Spring自动装配
  • C# 4.0 等待线程结束
  • C++ 入门14:STL 容器之向量(vector)
  • C++基础(二)
  • SourceTree rebase(变基)的使用
  • Gooxi受邀参加第三届中国数据中心服务器与设备峰会
  • AGI 之 【Hugging Face】 的【问答系统】的 [评估并改进问答Pipeline] / [ 生成式问答 ] 的简单整理
  • django ninja get not allowed 能用 put delete
  • 2.The DispatcherServlet
  • GitHub连接超时问题 Recv failure: Connection was reset
  • MacOS 通过Docker安装宝塔面板搭建PHP开发环境
  • 输入网址到网页显示的过程
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • Brief introduction of how to 'Call, Apply and Bind'
  • C# 免费离线人脸识别 2.0 Demo
  • Java的Interrupt与线程中断
  • JDK9: 集成 Jshell 和 Maven 项目.
  • MySQL主从复制读写分离及奇怪的问题
  • October CMS - 快速入门 9 Images And Galleries
  • PAT A1017 优先队列
  • spring security oauth2 password授权模式
  • Spring技术内幕笔记(2):Spring MVC 与 Web
  • Windows Containers 大冒险: 容器网络
  • yii2中session跨域名的问题
  • 基于 Babel 的 npm 包最小化设置
  • 前端之Sass/Scss实战笔记
  • 容器服务kubernetes弹性伸缩高级用法
  • 使用阿里云发布分布式网站,开发时候应该注意什么?
  • 算法-插入排序
  • 源码之下无秘密 ── 做最好的 Netty 源码分析教程
  • 正则表达式
  • Nginx惊现漏洞 百万网站面临“拖库”风险
  • 哈罗单车融资几十亿元,蚂蚁金服与春华资本加持 ...
  • 容器镜像
  • ​插件化DPI在商用WIFI中的价值
  • ​第20课 在Android Native开发中加入新的C++类
  • ​决定德拉瓦州地区版图的关键历史事件
  • ###STL(标准模板库)
  • #如何使用 Qt 5.6 在 Android 上启用 NFC
  • #微信小程序(布局、渲染层基础知识)
  • $forceUpdate()函数
  • (C#)一个最简单的链表类
  • (javascript)再说document.body.scrollTop的使用问题
  • (超详细)语音信号处理之特征提取
  • (初研) Sentence-embedding fine-tune notebook
  • (附源码)php投票系统 毕业设计 121500
  • (附源码)springboot 基于HTML5的个人网页的网站设计与实现 毕业设计 031623
  • (附源码)ssm基于web技术的医务志愿者管理系统 毕业设计 100910
  • (附源码)ssm失物招领系统 毕业设计 182317
  • (篇九)MySQL常用内置函数
  • (四)图像的%2线性拉伸
  • (一)utf8mb4_general_ci 和 utf8mb4_unicode_ci 适用排序和比较规则场景