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

news2024/9/22 9:56:52

功能:

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。

周视图效果图: 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1928497.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MWA(Modern Web App)初学那些事-2-Basic HTML CSS

初学MWA(Modern Web App&#xff09;那些事-2-Basic HTML & CSS 目录 初学MWA(Modern Web App&#xff09;那些事-2-Basic HTML & CSS前言一、本节学习目标二、HTML基础内容2.1关键元素2.4 Scripts 三、CSS 基础内容3.1 级联样式表-用于设置网页样式和布局3.2 CSS规则语…

Docker的虚拟化安装、常用命令和使用案例

文章目录 一、Docker的虚拟机安装1、完成虚拟机的更新2、完成Docker安装3、配置镜像加速器 二、Docker常用命令三、Docker的容器创建四、理解虚拟机中的Docker容器 一、Docker的虚拟机安装 1、完成虚拟机的更新 详见我的文章。 2、完成Docker安装 yum list installed|grep …

筑梦未来,精准构建:Chief Architect Premier X10 for Mac,首席建筑师的专业之选

Chief Architect Premier X10 for Mac&#xff0c;是建筑设计领域的一款顶尖软件&#xff0c;专为追求卓越设计与精准构建的用户量身打造。它融合了先进的3D建模技术与直观的操作界面&#xff0c;让设计师能够轻松实现创意与现实的完美融合。 这款软件提供了丰富的设计工具与资…

axios 下载大文件时,展示下载进度的组件封装——js技能提升

之前面试的时候&#xff0c;有遇到一个问题&#xff1a;就是下载大文件的时候&#xff0c;如何得知下载进度&#xff0c;当时的回复是没有处理过。。。 现在想到了。axios中本身就有一个下载进度的方法&#xff0c;可以直接拿来使用。 下面记录一下处理步骤&#xff1a; 参考…

【C++之C++11特性知识】

C学习笔记---026 C之C11特性知识1、C11特性知识介绍2、auto关键字3、范围for4、列表初始化5、final 与 override关键字6、lambda表达式7、右值引用和移动语义8、智能指针9、类型推导&#xff08;decltype关键字&#xff09;10、参考文档 C之C11特性知识 前言&#xff1a; 前面…

LVS+Nginx高可用集群---keepalived原理与实战

1.高可用集群架构keepalived双机主备原理 高可用&#xff1a;(HA) 部署nginx存在两台nginx。当主节点的nginx宕机停止服务的时候&#xff0c;nginx备用机起到跟nginx(主) keepalived的概念&#xff1a;解决单点故障&#xff1b;组件免费&#xff1b;可以实现高可用HA机制&…

css-grid布局(栅格布局)

css新世界-auto-fit grid 一个比flex更强大的布局,适合做整体布局 grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); auto-fit的话有strech效果gap 不仅可以用于grid 也可用flex. 在grid-template-areas表示这个位置空着grid area 的 [a b]命名可重复命名 表示的…

AutoHotKey自动热键(十一)下载SciTE4AutoHotkey-Plus的中文增强版脚本编辑器

关于AutoHotkey的专用编辑器, SciTE4AutoHotkey是一个免费的基于 SciTE 的 AutoHotkey 脚本编辑器,除了 DBGp 支持, 它还为 AutoHotkey 提供了语法高亮, 调用提示, 参数信息和自动完成, 以及其他拥有的编辑特性和辅助工具.XDebugClient 是一个基于 .NET Framework 2.0 的简单开…

视频号矩阵系统,AI自动生成文案,实现批量上传视频和定时发布

在数字化浪潮席卷全球的今天&#xff0c;视频内容已成为信息传播的重要载体。然而&#xff0c;对于众多自媒体创作者和企业而言&#xff0c;如何高效、精准地发布视频内容&#xff0c;依然是一个不小的挑战。幸运的是&#xff0c;随着技术的不断进步&#xff0c;视频号矩阵系统…

SpringBatch文件读写ItemWriter,ItemReader使用详解

SpringBatch文件读写ItemWriter&#xff0c;ItemReader使用详解 1. ItemReaders 和 ItemWriters1.1. ItemReader1.2. ItemWriter1.3. ItemProcessor 2.FlatFileItemReader 和 FlatFileItemWriter2.1.平面文件2.1.1. FieldSet 2.2. FlatFileItemReader2.3. FlatFileItemWriter 3…

c++ primer plus 第16章string 类和标准模板库,16.1.3 使用字符串

c primer plus 第16章string 类和标准模板库,16.1.3 使用字符串 c primer plus 第16章string 类和标准模板库,16.1.3 使用字符串 文章目录 c primer plus 第16章string 类和标准模板库,16.1.3 使用字符串16.1.3 使用字符串程序清单16.3 hangman.cpp 16.1.3 使用字符串 现在&a…

使用 PyAMF / Django 实现 Flex 类映射

1、问题背景 PyAMF 是一个用于在 Flex 和 Python 之间进行通信的库&#xff0c;在使用 PyAMF 与 Flex 应用进行通信时&#xff0c;经常会遇到错误。例如&#xff0c;在发送一个 Flex Investor 对象到 Python 时&#xff0c;会得到一个 ‘KeyError: first_name’ 的错误。这是因…

大数据面试SQL题-笔记01【运算符、条件查询、语法顺序、表连接】

大数据面试SQL题复习思路一网打尽&#xff01;(文档见评论区)_哔哩哔哩_bilibiliHive SQL 大厂必考常用窗口函数及相关面试题 大数据面试SQL题-笔记01【运算符、条件查询、语法顺序、表连接】大数据面试SQL题-笔记02【...】 目录 01、力扣网-sql题 1、高频SQL50题&#xff08…

人工智能算法工程师(中级)课程14-神经网络的优化与设计之拟合问题及优化与代码详解

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能算法工程师(中级)课程14-神经网络的优化与设计之拟合问题及优化与代码详解。在机器学习和深度学习领域&#xff0c;模型的训练目标是找到一组参数&#xff0c;使得模型能够从训练数据中学习到有用的模式&am…

mysql(5.5)启动服务和环境配置

正常启动 参考&#xff1a;Javaweb基础之mysql回溯笔记(一) 总的来说就是在mysql的安装目录下&#xff0c;找到bin下面的msyqld.exe&#xff0c;双击即启动了mysql服务&#xff1b; 启动方式二 也可以直接找到windows的服务项进行启动&#xff0c;操作如下&#xff1a; 打开…

eclipse免安装版64位 2018版本

前言 eclipse是一个开放源代码的、基于Java的可扩展开发平台。就其本身而言&#xff0c;它只是一个框架和一组服务&#xff0c;用于通过插件组件构建开发环境。 一、下载地址 下载地址&#xff1a;http://source/download 选择如下图红色框文件内容下载 二、安装步骤 1、…

社交电商的新篇章:AI智能名片O2O商城小程序与传统微商的区别与融合

摘要 在数字经济蓬勃发展的今天&#xff0c;互联网技术的革新正以前所未有的速度重塑着商业格局。传统微商模式&#xff0c;尽管在初期借助社交媒体迅速崛起&#xff0c;但因其固有的局限性&#xff0c;如产品质量不一、营销手段单一、信任机制脆弱等&#xff0c;逐渐暴露出诸…

【实战场景】MongoDB迁移的那些事

【实战场景】MongoDB迁移的那些事 开篇词&#xff1a;干货篇【MongoDB迁移的方法】&#xff1a;1. 基于mongodump和mongorestore的迁移一、迁移前准备二、使用mongodump备份数据三、使用mongorestore还原数据四、注意事项 2. 基于MongoDB复制集的迁移一、迁移前准备二、配置新复…

Spring Boot整合Minio实现文件上传和读取

文章目录 一、简介1.分布式文件系统应用场景2.Minio介绍3.Minio优点 二、docker部署&#xff08;windows系统&#xff09;1.创建目录2.拉取镜像3.创建容器并运行4.访问控制台5.初始化配置 三、Spring Boot整合Minio1.创建demo项目2.引入依赖3.配置4.编写配置类5.MinIO工具类6.文…

ASP.NET Core----基础学习08----MVC中的属性路由

文章目录 1.MVC 中属性路由2.如果控制器名称与路由的第一级名称不一致3.指定读取的视图文件4.指定路由的一级 & 二级目录 1.MVC 中属性路由 step1&#xff1a; 在Startup.cs文件中设置仅使用UseMvc&#xff08;不包含路由的设置&#xff09; step2&#xff1a; 在控制器中…