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

背景

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

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

使用

按需加载数据(五)

回顾下前文,我们自定义扩展了显示全部任务还是只显示未结束的任务,因FullCalendar自身组件功能限制,切换时,通过刷新当前页面来实现。在刷新操作处理中,调用了tab页刷新,将当前用户操作的视图类型和是否显示全部的标识位以query参数的方式进行传递。

// 刷新
refresh() {const fullCalendar = this.$refs.fullCalendar.calendarlet query = this.$route.queryquery = Object.assign(query, {viewType: fullCalendar.view.type,showAllFlag: this.showAllFlag})refreshSelectedTagWithQuery(query)
}

在页面初始化时,从query参数中获取到视图类型,调用FullCalendar组件的内置changeView方法来切换视图。

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

当时测试时查看后端情况,发现还有个小瑕疵,就是页面加载的时候,实际会触发两次调用后端服务请求,推测一次是来源于组件自身初始化加载,另一次是我们手工调用的api方法来切换视图。当时觉得只有在切换显示范围时才会触发,影响很小,先搁置了。
在使用过程中,这两次加载产生了严重的问题,表现为加载或刷新页面时,会出现事件不显示的情况。经深入分析和排查,问题就出在两次加载上。

举例说明,假设FullCalendar的默认视图initialView属性设置为日视图timeGridDay。
用户第一次访问页面,FullCalendar组件加载时会触发一次视图,然后我们又调用了一次切换视图,在加载事件数据的方法中打印,查看控制台和后端请求,确实调用了两次。

// 加载事件数据
loadEvent(fetchInfo, successCallback, failureCallback) {console.log('loadEvent')this.startTime = this.$dateFormatter.formatUTCTime(fetchInfo.start)this.endTime = this.$dateFormatter.formatUTCTime(fetchInfo.end)this.successCallback = successCallbackthis.loadData()
}

这一点我们可以优化,即判断当前视图与要切换的目标视图是否同一个,相同则不再调用。

 // 初始化
init() {this.calendarApi = this.$refs.fullCalendar.getApi()// 处理是否显示全部if (this.$route.query.showAllFlag != undefined) {//此处注意,query参数是字符串类型,直接赋值给showAllFlag会令其类型变化,使用非运算符!会一直为truethis.showAllFlag = this.$route.query.showAllFlag == 'true' ? true : false}// 默认设置视图类型let viewType = this.calendarOptions.initialView// query参数中取值if (this.$route.query.viewType) {viewType = this.$route.query.viewType}// 当前视图与要切换的目标视图不是同一个时,调用日历组件api实现视图切换if (viewType != this.calendarOptions.initialView) {const fullCalendar = this.$refs.fullCalendar.calendarfullCalendar.changeView(viewType)}
}

调整后查看控制台,只输出一次了。
在完成页面首次访问后,用户点击顶部右侧按钮“月”、“周”、“列表”切换视图,都能正常显示。
当用户切换到周视图后,点击查看范围切换按钮时,这时候实际进行了页面重新加载,查看后端调用了两次数据查询服务。因为初始化视图是日视图,最后要展现的是周视图。一次来源于FullCalendar的初始化,一次来源于我们手工调用api方法。这时候发生的问题就在于,这两次数据绑定,看上去仍会只会生效一次,有时候绑定的是单天的数据,有时候绑定的是一周的数据,这样会导致在周视图下,因为加载的数据是单天的,周视图中其余六天的数据没有显示,就跟“丢失”一样。
给调用切换视图的api设置了延迟3秒执行,如下所示:

setTimeout(() => {const fullCalendar = this.$refs.fullCalendar.calendarfullCalendar.changeView(viewType)
}, 3000)

然后测试,发现数据绑定和加载正常了,只是3秒的延迟对用户体验很大。
基于上述验证思考,推测问题的根源我们使用了“全局”变量successCallback缓存了回调方法,两次视图加载执行时间非常接近,该变量被错误的赋值。

动手尝试,去除全局变量successCallback(data根目录下变量),将加载事件数据中的successCallback的值通过方法参数传递,如下:

    // 加载事件数据loadEvent(fetchInfo, successCallback, failureCallback) {console.log('loadEvent')this.startTime = this.$dateFormatter.formatUTCTime(fetchInfo.start)this.endTime = this.$dateFormatter.formatUTCTime(fetchInfo.end)this.loadData(successCallback)},// 加载数据loadData(successCallback) {this.$api.personaltask.task.listWithScope(this.startTime, this.endTime).then((res) => {if (res.data) {const eventArray = res.data.map((item) => {// 若起止时间均为00:00:00,则设置为allDay属性为truelet allDay = falseif (item.startTime &&item.endTime &&item.startTime.substr(11, 8) === '00:00:00' &&item.endTime.substr(11, 8) === '00:00:00') {allDay = true}return {id: item.id,title: item.name,start: item.startTime,end: item.endTime,allDay: allDay,status: item.status,extendedProps: {priority: item.priority,plannedDuration: item.plannedDuration}}})this.eventData = eventArraythis.filteData(successCallback)}})},// 筛选数据filteData(successCallback) {if (this.showAllFlag == true) {this.calendarOptions.customButtons.changeShowScopeButton.text = '显示未结束'successCallback(this.eventData)} else {this.calendarOptions.customButtons.changeShowScopeButton.text = '显示全部'const filtedData = this.eventData.filter((item) => {return (item.status === 'IN_PROGRESS' ||item.status === 'TO_DO' ||item.status === 'EXPIRED' ||item.status === 'PENDING' ||item.status === 'PAUSED')})successCallback(filtedData)}},

测试结果终于正常了。

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

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

相关文章

记Windows环境下JDK安装配置

写在文章开头 这是笔者非常早期接触Java时写的文章,为方便每次系统重装时能够快速完成JDK解压版安装配置遂用此文记录了一下整个过程。 Hi,我是 sharkChili ,是个不断在硬核技术上作死的 java coder ,是 CSDN的博客专家 &#x…

springboot和mybatis项目学习

#项目整体样貌 ##bean package com.example.demo.bean;public class informationBean {private int id;private String name;private String password;private String attchfile;public int getId() {return id;}public String getName() {return name;}public String getPas…

基于Java技术的ERP管理系统:企业资源规划的先进解决方案

在当前数字化转型的趋势下,企业对于高效、稳定且具备扩展性的管理系统的需求日益增加。为了满足这一需求,我们开发了一款基于Java技术的鸿鹄ERP(企业资源规划)管理系统。该系统采用了Spring Cloud Alibaba、Spring Boot、MybatisP…

Unity Protobuf+RPC+UniTask

远程过程调用(RPC)协议详解 什么是RPC协议RPC的基本原理RPC的关键组件RPC的优缺点Protobuf函数绑定CallEncodeRecvDecodeSocket.Send和Recv项目地址 什么是RPC协议 远程过程调用(Remote Procedure Call,简称RPC)是一种…

WPF学习(1)--类与类的继承

在面向对象编程中,继承是一种机制,允许一个类(称为子类或派生类)从另一个类(称为父类或基类)继承属性和方法。继承使我们能够创建一个通用类,然后根据需要扩展或修改它以创建更具体的类。以下是…

适合小白学习的项目1832javaERP管理系统之成本管理Myeclipse开发mysql数据库servlet结构java编程计算机网页项目

一、源码特点 java 成本管理系统 是一套完善的web设计系统,对理解JSP java编程开发语言有帮助采用了serlvet设计,系统具有完整的源代码和数据库,系统采用web模式,系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发…

工作手机安全管理平台建设方案

第一章 项目背景 移动互联网的时代,各个行业在在推进移动办公和掌上办公,通过智能手机、平板电脑等进行线上办公,这样能提高了企业人员的办公效率,从而为客户提供更及时的服务。 在移动办公提高了工作人员办公效率的同时&#xf…

codegeex2-6b-int4 部署

codegeex2-6b-int4 模型文件 CodeGeeX2 仓库文件地址 CodeGeeX2 推理教程 conda create -n codegeex2 python3.10 -y conda activate codegeex2 pip install -r requirements.txt -i https://pypi.mirrors.u…

抓包工具 Wireshark 的下载、安装、使用、快捷键

目录 一、什么是Wireshark?二、Wireshark下载三、Wireshark安装四、Wireshark使用4.1 基本使用4.2 过滤设置1)捕获过滤器2)显示过滤器 4.3 过滤规则1)捕获过滤器-规则语法2)显示过滤器-规则语法 4.4 常用的显示过滤器规…

94. 二叉树的中序遍历(Swift实现, 迭代)

题目描述 使用迭代方法解题 class TreeNode {var val: Intvar left: TreeNode?var right: TreeNode?init(_ val: Int) {self.val valself.left nilself.right nil} }func inorderTraversal(_ root: TreeNode?) -> [Int] {var result [Int]() // 用于存储中序遍历…

kali中安装zsteg教程

1、下载文件 git clone http://www.github.com/zed-0xff/zsteg 2、第一步需要保证虚拟机是有网络的,不然无法克隆 3、可以将网络设置成如下后重启,访问百度看看能不能访问,若可以访问,则进行下一步 4、查看源,删除源&…

Python-程序流程控制

目录 1. 分支语句 1.1 if 1.2 if-else 1.3 if-elif-else 2. 循环语句 2.1 while 2.2 for 3.跳转语句 3.1 break 3.2 continue 1. 分支语句 1.1 if aint(input("请输入成绩")) if a>100:print ("牛逼") if a<60:print("不牛逼")1.2 if-e…

期末复习5---PTA

以下是提交正确的代码&#xff1a; int max_len( char *s[], int n ) {int i;int max0;for(i1;i<n;i){if(strlen(s[i])>strlen(s[max]))maxi;}return strlen(s[max]); } 以下是我自己写的代码&#xff1a; 出现的问题是 &#xff1a;括号加的不对&#xff0c;需要细心…

同城如何异地共享文件?

在现代社会中&#xff0c;跨地区的合作变得越来越普遍&#xff0c;而这也带来了共享文件的需求。当我们身处不同的城市&#xff0c;如何高效地共享文件已经成为一项迫切的需求。本文将介绍一种名为“同城异地共享文件”的解决方案&#xff0c;帮助解决这一问题。 2. 天联组网—…

二手物品交易系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;商家管理&#xff0c;用户管理&#xff0c;商品管理&#xff0c;用户咨询管理 商家账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;商品管理&#xff0c;用…

LogicFlow 学习笔记—7. LogicFlow 基础 背景 Background

背景 Background 提供可以修改画布背景的方法&#xff0c;包括背景颜色或背景图片&#xff0c;背景层位于画布的最底层。 info 创建画布时&#xff0c;通过 background 选项来设置画布的背景层样式&#xff0c;支持透传任何样式属性到背景层。默认值为 false 表示没有背景。 …

SAP Web IDE 安装使用

For training SAP Web IDE 是基于 Eclipse 内核的在线开发 IDE&#xff0c;可以使用在线的试用版本&#xff0c;但服务器在德国&#xff0c;访问的网速特别慢。也可以使用 Personal Edition&#xff0c;在本机启动和编写代码。 打开官网下载WEBIDE工具包&#xff0c;包含 Tri…

开源AGV调度系统OpenTCS中的路由器(router)详解

OpenTCS中的任务分派器router详解 1. 引言2. 路由器(router)2.1 代价计算函数&#xff08;Cost functions&#xff09;2.2 2.1 Routing groups2.1 默认的停车位置选择2.2 可选停车位置属性2.3 默认的充电位置选择2.4 即时运输订单分配 3. 默认任务分派器的配置项4. 参考资料与源…

C#——析构函数详情

析构函数 C# 中的析构函数&#xff08;也被称作“终结器”&#xff09;同样是类中的一个特殊成员函数&#xff0c;主要用于在垃圾回收器回收类实例时执行一些必要的清理操作。 析构函数: 当一个对象被释放的时候执行 C# 中的析构函数具有以下特点&#xff1a; * 析构函数只…

简单了解RS485与RS232(UART)

简单了解RS485与RS232&#xff08;UART&#xff09; 一、UART和RS232、RS485的关系1、UART2、RS232/RS4853、RS232 与 RS485 的区别与联系 二、Modbus协议说明1、什么是协议2、Modbus协议说明3、Modebus通信过程4、Modbus存储区5、Modbus协议类型6、Modbus功能码 三、stm32HC-S…