FullCalendar5 + Vue使用记录

4,450 阅读2分钟

1. 安装和使用

1.1 安装以下npm包

npm install --save @fullcalendar/vue @fullcalendar/core  // 核心库
npm install --save @fullcalendar/interaction   // 交互库 
npm install --save @fullcalendar/moment    // 格式化时间库。可以在插件使用YYYY MM
npm install --save @fullcalendar/daygrid // 月视图

1.2 使用

<template>
   <FullCalendar
        class="fullCalendar"
        :options="calendarOptions"
        ref="fullCalendar"/>
</template>
<script>
import FullCalendar from '@fullcalendar/vue' // 核心库
import InteractionPlugin from '@fullcalendar/interaction' // 交互库
import MomentPlugin from '@fullcalendar/moment' // 格式化时间库。可以在插件使用YYYY MM
import DaygridPlugin from '@fullcalendar/daygrid' // 月视图
export default {
     components: {
         FullCalendar
     },
     data () {
         return {
             calendarOptions: {
                 // 默认视图:月视图
                 initialView: 'dayGridMonth',
                 // 是否显示周六、周日
                 weekends: false,
                 // 引入插件, 如果有多个视图最好都先添加进去。
                 plugins: [ 
                    InteractionPlugin,
                    MomentPlugin,
                    DaygridPlugin
                 ]
             }
         }
     }
}
</script>

1.3 需要注意的几点

  1. 我使用的版本都是5.9.0版本。(每个版本dom结构都会有一点小变化,不是特需最好不要升降版本)
  2. 不要给FullCalendar组件绑定动态属性或者动态方法。
  3. 一个页面有多个视图(日、周、月)一定要注意样式冲突问题。每个视图都有单独的class。
  4. FullCalendar5选项和方法一定要写在options对象中,FullCalendar4选项配置是直接写在组件内的。这和5是最大的区别(dom结构也发生很大变化)。
  5. 如果想要加载不同视图可以点击插件链接查看

2 API说明

2.1 FullCalendar4与FullCalendar5的API区别

FullCalendar5增加很多API和钩子函数,在修改和增加一些新的功能上比4版本更加方便。能升级到版本5就使用5
例:想要修改和添加月视图每个单元格的文本内容和class可以使用dayCellContentdayCellClassNames

2.2 API官网链接

本来想的是根据自己理解把API给翻译翻译,后来发现官网不用科学上网也可以上去。

官网:fullcalendar.io/docs#toc
插件:fullcalendar.io/docs/plugin…
版本5和4之间的差异:fullcalendar.io/docs/upgrad…

3 在项目遇到的一些问题

3.1 视图样式修改问题

插件的样式对于项目而言或多或少都需要进行调整,在一个页面可能会有日、周、月、资源横向图、资源竖向图等。很多元素class名字都相同,只想要修改月视图内容里面的样式而不影响其它视图样式,需要外层不同class进行包裹。

我的做法是把每个视图当作不同模块进行处理,就算有通用样式也不会单独拎出来,这样保证我修改某个视图不会影响其它视图。

如:月视图内容包裹class类 .fc-dayGridMonth-view

.fc-dayGridMonth-view {
    // 子元素的内容样式
}
  1. 月视图: .fc-dayGridMonth-view
  2. 周视图: .fc-timeGridWeek-view
  3. 日视图: .fc-timeGridDay-view
  4. 垂直资源视图: .fc-resourceTimeGrid-view
  5. 时间轴视图: .fc-resourceTimeline-view

标题头所有的视图使用的同一个。

image.png

3.2 设置属性

3.2.1 直接赋值

this.calendarOptions.weekends = true

3.2.2 使用API设置

// getApi()是组件里面的方法。
this.$refs.fullCalendar.getAPi().setOption('weekends', true)

3.2.3 在不确定选项添加新的属性

比如选项customButtons有多个自定义按钮,想要动态新添加一个,可以试试这么做。

// 先获取customButtons值
let customButtonsOption = this.$refs.fullCalendar.getApi().getOption('customButtons');
// 然后再设置
this.$refs.fullCalendar.getApi().setOption('customButtons', {
    ...customButtonsOption,
    newBtn: {}
})

3.3 时间轴视图(resourceTimeline)左右横线对不齐

原因:右侧的滚动条是默认的不好看。所以滚动条是重新设置的样式。

遇到的问题:如果从右侧进行向下滚动,导致左侧的横向线与右侧的横向线对不齐。这是因为左侧并没有出现滚动条,右侧有滚动条,导致高度位置不一致。

解决方法:给左侧列表也设置一样的滚动条高度,如果不想显示滚动条,滚动条透明度为0。

3.4 设置垂直资源视图(resourceTimeGridDay)左侧时间宽度

image.png

/* 可以进行这么设置 找到col标签 */
.fc-scrollgrid > colgroup > col {
    min-width: 92px !important;
}

3.5 nowIndicatorContent(当前时间指示器)不触发

这个BUG目前我只是在resourceTimeline这个视图发现过。

功能:每分钟更新都会触发该回调。

问题:设置nowIndicatorContent回调并没有实时触发。

设置:如果是resourceTimeline视图设置slotDurationslotLabelInterval为1小时以上(包括一小时)就不会触发该回调函数。

解决方案:可以自己写一个分钟更新就调用的方法。注意:它不是每过一分钟就触发,假设当前时间为16:10:30。过了30秒到16:11:00。那么这个方法就该触发。

4. 我的配置选项

calendarOptions: {
        nowIndicator: true, // 是否显示当前时间轴
        allDaySlot: false,  // 是否显示全天
        slotEventOverlap: true, // 事件是否可重叠
        editable: false,  // 能否编辑事件。如果需要拖拽事件,必须开启它
        droppable: true,   // 是否把其它日历上的事件拖拽到这个日历上
        selectOverlap: false, // 用户选择时能否重叠到事件上, selectable必须为true才生效
        unselectAuto: true, // 选中时,点击页面其它位置是否取消选中
        selectable: true, // 允许用户点击或拖拽选中
        dayHeaders: true, // 是否显示日期标题
        dayMinWidth: 'auto',  // 日最小宽度,如果日期单元格没办法满足,会出现水平滚动条
        refetchResourcesOnNavigate: true, // 当用户切换不同视图时,是否重新加载数据
        resourceOrder: 'index', // 资源按照index属性排序
        locale: util.cookies.get('lang').indexOf('en') > -1 ? 'en' : 'zh-cn', // 中英文
        initialView: "dayGridMonth", // 默认视图
        schedulerLicenseKey: "", // key,需要花钱
        height: bodyHeight - 68, // 日历整体高度
        eventSources: [], // 事件列表
        resources: [], // 资源列表
        plugins: [   // 用到的插件
          momentPlugin,
          dayGridPlugin,
          timeGridPlugin,
          resourceTimelinePlugin,
          interactionPlugin,
          resourceTimeGridPlugin,
          scrollgridPlugin
        ],
        headerToolbar: { // 标题显示的按钮和文本。
          left: 'prev,title,mothTitle,next,today',
          center: '',
          right: 'timeGridDay,timeGridWeek,dayGridMonth,timeline'
        },
        buttonText: { // 按钮的文本设置
          today: '今日',
          dayGridMonth: '月',
          week: '周',
          day: '日'
        },
        customButtons: {
          // 自定义button,如果想显示页面上,把timeline放到headerToolbar对象里。
          timeline: {
            text: '自定义',
            click: this.timelineEvent
          }
        },
        slotLabelFormat: 'HH:mm', // 资源视图的事件格式
        eventTimeFormat: 'HH:mm', // 事件事件格式
        dayMaxEvents: true,  // 在dayGrid视图中如果每个单元格事件超出单元格会出现'+more'
        resourceAreaWidth: '280px', // 横轴资源视图的左侧列表宽度
        // 每个视图不同显示的日期格式
        views: {
          timeGridDay: {
            titleFormat: { year: 'numeric', month: 'short', day: 'numeric'},
          },
          timeGridWeek: {
             titleFormat: { year: 'numeric', month: 'short' },
          },
          dayGridMonth: {
            titleFormat: { year: 'numeric', month: 'short' },
            displayEventTime: true
          },
          timeline: {
            titleFormat: { year: 'numeric', month: 'short', day: 'numeric'},
          },
          resourceTimeGrid: {
            titleFormat: { year: 'numeric', month: 'short', day: 'numeric'},
            duration: { days: 1 }
          }
        },
        eventShortHeight: 15, // 具有最小事件的样式
        slotDuration: "00:15", // 事件轴以15分钟为一刻度
        eventMinHeight: "15", // 事件最小高度
        // 出现+more会调用该回调。返回值为:文字或者DOM
        moreLinkContent:  (info) => this.$t('schedule.more') + info.num + this.$t('schedule.item'), 
        // 点击+more触发该回调
        moreLinkClick: this.eventLimitClickFun, 
        // title标题文本回调。返回值为:文本和DOM
        dayHeaderContent: this.columnHeaderHtmlFun, 
        // 取消选择回调
        unselect: this.unselectCallback,
        // 日期切换回调。注意:切换视图也会调用该回调。
        datesSet: this.handleDatesRender,
        // 点击事件
        eventClick: this.handleEventClick,
        // 切换视图
        viewDidMount: this.handleViewSkeletonRender,
        // 月视图每个单元格回调。返回值:文字或DOM
        dayCellContent: (info) => {
          return {html: `<a class="fc-daygrid-day-number">${info.dayNumberText.replace('日','')}</a>`}
        },
        // 现在指示器(nowIndicator)回调 
        nowIndicatorDidMount: this.nowIndicatorDidMount,
        // 到当前时间指示器时间显示。如果有返回值(文本或DOM):则显示返回值
        nowIndicatorContent: this.setNowIndicatorTime,
        // 日历尺寸发生改变
        windowResize: (arg) => {
          this.fullcalendarResize(arg.view.type)
        }
      },

5. 结束

目前我使用FullCalendar5遇到的这些问题,如果有遇到新的问题,会实时更新到这里。

如果你使用FullCalendar5遇到过其它问题也可以在评论区告诉我。