FullCalendar日历组件集成实战(16)

news2024/11/19 10:38:39

背景

有一些应用系统或应用功能,如日程管理、任务管理需要使用到日历组件。虽然Element Plus也提供了日历组件,但功能比较简单,用来做数据展现勉强可用。但如果需要进行复杂的数据展示,以及互动操作如通过点击添加事件,则需要做大量的二次开发。
FullCalendar是一款备受欢迎的开源日历组件,以其强大的功能而著称。其基础功能不仅免费且开源,为开发者提供了极大的便利,仅有少量高级功能需要收费。然而,尽管该组件功能卓越,其文档却相对简洁,导致在集成过程中需要开发者自行摸索与探索,这无疑增加了不少学习和验证的时间成本。
为此,本专栏通过日程管理系统的真实案例,手把手带你了解该组件的属性和功能,通过需求导向的方式,详细阐述FullCalendar组件的集成思路和实用解决方案。
在介绍过程中,我们将重点关注集成要点和注意事项,力求帮助开发者在集成过程中少走弯路,提供有效的避坑指南,从而提升开发效率,更好地利用这款优秀的日历组件。

官网:https://fullcalendar.io/
image.png
环境Vue3+Element Plus+FullCalendar 6.1.11。

使用

保持当前视图范围不变

当我们在月底使用日历组件制定下个月计划和日程,或者安排下周的工作,新增或修改事件后,后端数据持久化后通过刷新页面的方式来让日历组件上的数据更新。这样存在的问题在于一旦刷新页面,则日历组件会“跳”回到当天日期。
例如,制定6月份的计划,刚添加了1条数据,然后保存,视图又跳回了5月份,还需要手工再切换,明显不合理。

FullCalendar组件的切换视图的方法changeView,可以传入第二个参数,单个时间或者起止范围。

在前面的实现方式中,我们通过query参数保持当前的视图类型以及自定义的显示范围(全部任务/进行中任务),采用该方式,把当期视图的显示时间范围也通过query参数来传递,在刷新方法中处理:

    // 刷新
    refresh() {
      const fullCalendar = this.$refs.fullCalendar.calendar
      // console.log(fullCalendar.view)
      let query = this.$route.query
      query = Object.assign(query, {
        viewType: fullCalendar.view.type,
        showAllFlag: this.showAllFlag,
        start: this.$dateFormatter.formatUTCDate(fullCalendar.view.activeStart),
        end: this.$dateFormatter.formatUTCDate(fullCalendar.view.activeEnd)
      })
      refreshSelectedTagWithQuery(query)
    }

然后在页面初始化时读取query参数,调用切换视图方法:

    // 初始化
    init() {
      this.calendarApi = this.$refs.fullCalendar.getApi()
      // 处理是否显示全部
      if (this.$route.query.showAllFlag != undefined) {
        //此处注意,query参数是字符串类型,直接赋值给showAllFlag会令其类型变化,使用非运算符!会一直为true
        this.showAllFlag = this.$route.query.showAllFlag == 'true' ? true : false
      }
      // 默认设置视图类型
      let viewType = this.calendarOptions.initialView
      // query参数中取值
      if (this.$route.query.viewType) {
        viewType = this.$route.query.viewType
      }
      const fullCalendar = this.$refs.fullCalendar.calendar
      fullCalendar.changeView(viewType, {
        start: this.$route.query.start,
        end: this.$route.query.end
      })
    }

然后测试发现无效,依然显示的是当前时间。

然后手工写死测试,视图类型为日视图,传入单天,有效。

fullCalendar.changeView('timeGridDay', '2024-06-10')

视图类型为周,传入时间范围,无效!

 fullCalendar.changeView('timeGridWeek', { start: '2024-06-10', end: '2024-06-17' })

这就很无语了……
翻看了FullCalendar源码,看上去也没有问题:

changeView(viewType, dateOrRange) {
    this.batchRendering(() => {
        this.unselect();
        if (dateOrRange) {
            if (dateOrRange.start && dateOrRange.end) { // a range
                this.dispatch({
                    type: 'CHANGE_VIEW_TYPE',
                    viewType,
                });
                this.dispatch({
                    type: 'SET_OPTION',
                    optionName: 'visibleRange',
                    rawOptionValue: dateOrRange,
                });
            }
            else {
                let { dateEnv } = this.getCurrentData();
                this.dispatch({
                    type: 'CHANGE_VIEW_TYPE',
                    viewType,
                    dateMarker: dateEnv.createMarker(dateOrRange),
                });
            }
        }
        else {
            this.dispatch({
                type: 'CHANGE_VIEW_TYPE',
                viewType,
            });
        }
    });
}

停下来思考,推测日历展示的范围,不仅仅跟时间范围有关系,还跟目标时间有关系。
尝试调用内置方法gotoDate,源码调整如下:

  // 初始化
  init() {
    this.calendarApi = this.$refs.fullCalendar.getApi()
    // 处理是否显示全部
    if (this.$route.query.showAllFlag != undefined) {
      //此处注意,query参数是字符串类型,直接赋值给showAllFlag会令其类型变化,使用非运算符!会一直为true
      this.showAllFlag = this.$route.query.showAllFlag == 'true' ? true : false
    }
    // 默认设置视图类型
    let viewType = this.calendarOptions.initialView
    // query参数中取值
    if (this.$route.query.viewType) {
      viewType = this.$route.query.viewType
    }
    const fullCalendar = this.$refs.fullCalendar.calendar
    if (this.$route.query.start && this.$route.query.end) {
      fullCalendar.changeView(viewType, {
        start: this.$route.query.start,
        end: this.$route.query.end
      })
      // 取起止范围相差天数
      const dayCount = this.getDaysDifference(this.$route.query.start, this.$route.query.end)
      // 开始时间加上时间范围差值的一半,即取时间中间位置
      const targetDay = new Date(
        new Date(this.$route.query.start).getTime() + (dayCount / 2) * 24 * 60 * 60 * 1000
      )
      // 导航到指定日期
      fullCalendar.gotoDate(this.$dateFormatter.formatUTCDate(targetDay))
    } else {
      fullCalendar.changeView(viewType)
    }
  }

实现的关键逻辑就是获取到页面刷新前视图显示的起止时间范围,然后取中间的时间值,调用api跳转到该时间。
对于日视图和周视图,跳转时间直接取开始时间也可以正常运行,但是月视图不行,因为默认显示范围大于一个月,当前月以及上个月底的几天和下个月的前几天都会显示。如果也直接取开始时间作为跳转时间,则还是会出现在月底制定下个月计划时,页面刷新跳回到本月的情况。

通过以上方法,前端功能正常了,监控后端服务,调用gotoDate时,又触发了一次加载数据,也就是刷新页面,需要加载三次数据……组件自己初始化触发一次,调用切换视图触发一次,调用跳转到时间再触发一次。
这么做确实不优雅,相当于曲线救国,不清楚是组件自身问题或限制,只能这么干,还是有更好的实现方案,后续解决了再更新下本文。

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

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

相关文章

【Linux】Wmware Esxi磁盘扩容

目录 一、概述 1.1 磁盘分区概念 1.2 LVM概念 二、扩容步骤 二、报错 一、概述 1.1 磁盘分区概念 在 Linux 中,每一个硬件设备都映射到一个系统的文件,对于硬盘、光驱等 IDE 或 SCSI 设备也不例外。Linux把各种 IDE 设备分配了一个由 hd 前缀组成的文…

使用VBA隐藏图表中的系列

Excel中很多图表相关的操作,并不能通过录制宏得到代码,这个场景中,如下希望开发代码实现自动化,就会无从下手,其实只要找到相关的属性和方法,代码可能并不复杂。 Excel的线图如下所示,其中有三…

每日一学(面试考题)

1、ConCurrentHashMap为什么不允许key为null? 底层 putVal方法 中 如果key || value为空 抛出空指针异常 其实是为了避免在多线程并发场景下的歧义问题 在获取key 返回结果为null 无法判断是 put(k,v)的时候 value本身是n…

Python+Pytest+Allure+Yaml接口自动化测试框架详解

PythonPytestAllureYaml接口自动化测试框架详解 编撰人:CesareCheung 更新时间:2024.06.20 一、技术栈 PythonPytestAllureYaml 版本要求:Python3.7.0,Pytest7.4.4,Allure2.18.1,PyYaml6.0 二、环境配置 1、安装python3.7,并配置…

探索ONLYOFFICE桌面编辑器8.1:更强大的办公软件(新功能全新详解)

引入 时间到达2024年,办公软件已经成为不可或缺的的一部分。想到办公软件不知道大家首先想到那些产品 office 亦或是 WPS,但一个前者需要购买才能使用完整服务,一个漫天的弹广告不充会员什么都用不了。那难道世面上就没有一块正在好用无广告的…

一天跌20%,近500只下跌,低价可转债为何不香了?

6月以来,Wind可转债低价指数累计下跌7.3%,大幅跑输中价、高价转债。分析认为,市场调整的底层逻辑在于投资者对风险的重新评估和流动性的紧缩,宏观经济的波动和政策环境的不确定性、市场结构性的变化均对低价可转债市场产生了冲击。…

【 IM 服务】IM 翻译服务介绍

融云控制台 IM 翻译功能入口:IM 翻译 融云即时通讯业务提供 IM 翻译 插件,可为 IMLib 与 IMKit SDK 快速接入外部翻译服务,由融云服务端负责对接外部翻译服务供应商的鉴权、API 调用、账号管理、计费等流程。 提示: 1、该插件仅支…

COMSOL - 一个点光源是否总能照亮整个房间?

20 世纪 50 年代,数学家恩斯特施特劳斯(Ernst Straus)提出了一个有趣的问题:在一个侧壁由理想反射镜构成的任意形状的空房间里,一个点光源是否总能照亮整个房间?诺贝尔奖获得者罗杰彭罗斯(Roger…

背包模型——AcWing 423. 采药

背包模型 定义 背包模型是一种常见的算法问题模型,它主要涉及将一些物品放入一个容量有限的背包中,以达到某种最优目标,如最大化价值或最小化重量等。 运用情况 常用于资源分配、项目选择、货物装载等实际问题中。例如,在选择…

一次性掌握openlayers和cesium两个地图开发框架

又到一年毕业季,选择就业的同学,如果还没拿到offer,就要开始准备秋招了。 如果想找webgis相关的岗位,可以通过招聘信息,了解到企业的具体要求。其中,openlayers和cesium有多重要就不用我多说了。 掌握这两…

AI对职场的整顿

普通人离AI还有几年缓冲区,但早点做准备总是好的 AI淘汰的始终是跟不上时代的人。 现在很多公司都有AI培训,不仅GPT,还有Midjourney、Stable DIffusion等一系列AI工具。 像我们公司虽然今年招的少,但也会对新招的应届生统一进行…

VSCode运行前端项目-页面404

背景: 通过VSCode运行前端本地项目,运行成功后打开本地链接:http://1x.xxx.x.xxx:9803/ ,发现打开的页面重定向到404:http//1xx.xxx.x.xxx:9803/404; 并且控制台出现:Failed to load resource: …

邮件自动推送技术如何实现?有哪些优劣势?

邮件自动推送怎么设置?如何评估邮件自动推送的效果? 邮件自动推送是一种高效的电子邮件营销和通信技术,它能够根据预设条件自动发送邮件给特定的收件人。AokSend将深入探讨邮件自动推送技术的实现原理和注意事项。 邮件自动推送&#xff1a…

Java露营基地预约小程序预约下单系统源码

轻松开启户外探险之旅 🌟 露营热潮来袭,你准备好了吗? 随着人们对户外生活的热爱日益增加,露营已成为许多人周末和假期的首选活动。但你是否曾因找不到合适的露营基地而烦恼?或是因为繁琐的预约流程而错失心仪的营地…

手持小风扇品牌有哪些?分享口碑最好的五款手持小风扇

手持小风扇在炎热的夏季成为了许多人解暑的好帮手。它们不仅轻便便携,随时随地都能为我们带来清凉和舒适。然而,市场上手持小风扇的品牌繁多,让人眼花缭乱。为了帮助大家做出更明智的选择,接下来我们将分享口碑最好的五款手持小风…

Inventory Plus - Customizable Inventory System

InventoryPlus是一个直观而强大的工具,可以简化自定义库存、箱子和拾取的创建。该资产主要针对鼠标和键盘设计,但也支持游戏手柄。InventoryPlus可以处理您能想到的所有库存操作(如使用、装备、排序、丢弃等) 它通过调整TriggerAreas、PickUp和Chests的碰撞器类型,适用于3…

PPT录屏怎么录?PPT录屏,3种方法简单操作

在数字化时代,PPT已经成为我们日常工作、学习和生活中不可或缺的一部分。无论是商务报告、教学课件还是产品展示,PPT都能帮助我们更加生动、直观地传递信息。然而,有时候我们会面临PPT录屏怎么录的问题。这时,一个好的PPT录屏功能…

宝兰德受邀出席华为开发者大会2024,携手共绘基础软件新篇章

6月21日-23日,华为开发者大会(HDC 2024)在东莞松山湖举行,作为全球开发者的年度盛会,本次大会汇聚了众多业界精英与前沿技术。华为分享了HarmonyOS、盘古大模型、昇腾AI云服务、GaussDB数据库、自研仓颉编程语言等最新…

Streamer-Sales:开源数字人直播带货系统

Streamer-Sales 支持通过上传产品,一键生成带货话术,支持 RAG,支持文字转语音,支持基于 ComfyUI 合成虚拟人视频,可以直接在线体验,目前效果不是特别好,算是迈出第一步

Vue2中为啥不用 Object.defineProperty 实现响应式数组 ? 不能监听到数组变化吗?

Vue2.0 对于数据响应式的实现上是有一些局限性的,比如: 无法检测数组和对象的新增; 无法检测通过索引改变数组的操作; 针对以上问题,我们一般都会把锅甩给 Object.defineProperty。所以,在Vue 3.0 中&am…