FullCalendar日历组件集成系列8——事件处理

处理事件

新增事件

功能需求:日历组件的各视图中点击单元格区域或拖放单元格区域,新增事件,根据点击或拖放区域自动设置任务的开始时间和结束时间。
默认单元格都是只读的,需要首先配置属性selectable,让其可选中,然后配置选中事件,如下:

// 是否可以选中日历格
selectable: true,
//选中日历格事件
select: this.selectCell

如官方所说,对于封装的vue组件,不再区分vue的属性props和事件event,都以键值对方式放在配置选项options中。
事件回调参数是1个对象,输出log看下大致的数据结构如下:
image.png
从需求出发,通过日历的方式来新增任务,主要是想拿到起止时间,从start和end两个属性里就可以获取到。

引入新增任务的页面,如下:

import AddPage from '../task/add.vue'

然后在日历组件的select事件中调用,传入起止时间。

//选中日历格事件
selectCell(arg) {
  // 转换时间格式
  const startTime = this.$dateFormatter.formatUTCTime(arg.start)
  const endTime = this.$dateFormatter.formatUTCTime(arg.end)
  // 调用新增任务
  this.$refs.addPage.init({ startTime, endTime })
}

拖放结束后,弹出对话框,新增任务,自动填充时间,效果如下:
image.png
保存后,调用addTask方法,如下所示:

<AddPage ref="addPage" @refresh="addTask" />

// 新增任务
addTask(task) {
  // 获取日历对象
  const fullCalendar = this.$refs.fullCalendar.calendar
  // 将任务数据转换为日历事件
  const event = this.convertTaskToEvent(task)
  // 调用api添加任务
  fullCalendar.addEvent(event)
}

// 任务数据转换为事件对象
convertTaskToEvent(task) {
  // 计算全天事件属性值
  const allDay = this.calculateAllDay(task.startTime, task.endTime)
  // 数据转换
  return {
    id: task.id,
    title: task.name,
    start: task.startTime,
    end: task.endTime,
    allDay: allDay,
    extendedProps: {
      status: task.status,
      plannedDuration: task.plannedDuration
    }
  }
},
 // 计算全天事件属性值
calculateAllDay(startTime, endTime) {     
  let allDay = false
   // 若起止时间不为空且均为00:00:00,则设置为allDay属性为true
  if (
    startTime &&
    endTime &&
    startTime.substr(11, 8) === '00:00:00' &&
    endTime.substr(11, 8) === '00:00:00'
  ) {
    allDay = true
  }
  return allDay
}  

其核心逻辑就是调用FullCalendar官方提供的api方法addEvent来实现事件的添加,效果如下:
image.png

修改事件

点击事件时,希望打开事件查看界面,如需调整也可以直接修改,这时候调用的就是任务修改页面了。
引入修改任务的页面,如下:

import ModifyPage from '../task/modify.vue'

设置事件点击的回调,在回调中调用修改任务的页面,如下:

// 事件点击
eventClick: this.showModifyForm


// 显示修改表单
showModifyForm(arg) {
  this.$refs.modifyPage.init(arg.event.id)
}

效果如下:
image.png
点击保存按钮后,调用修改任务方法。

对于修改事件,FullCalendar并未提供一个像新增事件addEvent类似的事件,而是提供了一组事件。

需要通过日历对象的getEventById方法,通过事件id拿到事件对象。
然后调用事件对象的以下方法:
设置非时间相关的属性,使用event.setProp( name, value ),比如事件的标题。
设置时间相关的属性,使用以下方法:
setStart
setEnd
setAllDay
设置扩展属性,使用event.setExtendedProp( name, value ),比如我们自定义的任务状态。

对于修改任务,综合运用上述方法,实现如下:

// 修改任务
modifyTask(task) {
  const fullCalendar = this.$refs.fullCalendar.calendar
  const event = fullCalendar.getEventById(task.id)
  event.setProp('title', task.name)
  event.setStart(task.startTime)
  event.setEnd(task.endTime)
  let allDay = this.calculateAllDay(task.startTime, task.endTime)
  event.setAllDay(allDay)
  event.setExtendedProp('status', task.status)
  event.setExtendedProp('plannedDuration', task.plannedDuration)
}

通过拖动调整起止时间

在各日历视图中,可以通过拖拽的方式,来快速调整起止时间。例如,在日视图中,某个会议延期,由8:30开始顺延到9:30。
日历组件的事件默认不能拖动,需要配置editable为true,如下:

// 是否可以编辑,影响拖动
editable: true

前端显示起止时间在变,但是刷新页面又会恢复原状,这是因为该拖动只是做了前端的工作,需要调用后端服务,来把数据更新入库。
查找日历组件的触发事件,对应着eventDrop。
配置事件及处理,如下:

//事件拖动结束
eventDrop: this.eventDrop
 // 拖动结束
  eventDrop(arg) {
    const task = arg.event
    // 转换时间格式
    const startTime = this.$dateFormatter.formatUTCTime(task.start)
    const endTime = this.$dateFormatter.formatUTCTime(task.end)
    this.$api.task.task.changeTime(task.id, startTime, endTime)
  }

通过缩放调整起止时间

除了可以通过拖动来变更起止时间外,FullCalendar还支持将将鼠标悬停边界进行缩放,也就是对应着起止时间范围的放大或缩小,可以将单日的事件横向拖动变成跨越多天,也可以将5小时的事件纵向拖动缩短为2小时。
查找事件,结果有三个:

  • eventResizeStart
  • eventResizeStop
  • eventResize

如业务需求上不需要细分是起始时间变化还是结束时间变化,因此只需要使用最后一个eventRize就行了。
配置事件如下:

 //缩放事件
 eventResize: this.eventResize

添加处理,由于缩放和拖动,都是调整起止时间,因此可以完全复用后端处理,做了重构,调用同一个方法,如下:

  // 拖动结束
  eventDrop(arg) {
    this.changeTime(arg)
  },
  // 缩放结束
  eventResize(arg) {
    this.changeTime(arg)
  },
  // 变更时间
  changeTime(arg) {
    const task = arg.event
    // 转换时间格式
    const startTime = this.$dateFormatter.formatUTCTime(task.start)
    const endTime = this.$dateFormatter.formatUTCTime(task.end)
    this.$api.task.task.changeTime(task.id, startTime, endTime)
  }

注意,进行了上述设置后,只有时间块的下边缘可以缩放,即只支持结束时间的缩放。
如需要开始时间也支持缩放,需要再设置一个开关eventResizableFromStart为true,如下:

// 允许开始时间缩放
eventResizableFromStart: true

删除事件

在日历视图中右键一个现有任务后,弹出菜单中可以选择“删除”,如下所示:
image.png
原处理逻辑如下:

// 事件右键菜单命令
eventContextMenuSelect(command) {
  const id = this.contextMenuEventId
  if (command === 'copy') {
    this.$api.personaltask.task.addSingleByCopy(id).then((res) => {
      this.$refs.modifyPage.init(res.data.id)
    })
  } else if (command === 'remove') {
    this.$confirm('此操作将移除任务, 是否继续?', '确认', {
      type: 'warning'
    })
      .then(() => {
        this.$api.personaltask.task.remove(id).then(() => {
          this.refresh()
        })
      })
      .catch(() => {
        this.$message.info('已取消')
      })
  } else if (command === 'addLog') {
    this.addLog(id)
  } else if (command === 'setCompleted') {
    this.setCompleted(id)
  } else if (command === 'setPending') {
    this.setPending(id)
  }
  // 隐藏右键菜单
  this.eventContextMenu.visible = false
}

若实现无刷新,则需要在调用后端删除操作完成后,调用FullCalendar的删除事件api,removeEvent,我们封装一个删除任务的方法如下:

// 删除任务
revmoveTask(taskId) {
  const fullCalendar = this.$refs.fullCalendar.calendar
  const event = fullCalendar.getEventById(taskId)
  event.remove()
}

复制事件

通过复制一个现有事件来快速新增事件,先调用的后端的新增操作,完成拷贝属性,返回给前端id,然后调用修改任务的表单,保存后最终调用的是FullCalendar的addEvent,来实现将通过复制新建的事件添加到日历中显示,实现如下:

引入modifyPage,将其组件命名修改为CopyPage,如下:

import CopyPage from '../task/modify.vue'

然后设定回调方法,如下:

<CopyPage ref="copyPage" @refresh="addTask" />

回调的依旧是新增任务的方法,跟前面新增页面保存的回调是一致的,如下:

 // 新增任务
addTask(task) {
  // 获取日历对象
  const fullCalendar = this.$refs.fullCalendar.calendar
  // 将任务数据转换为日历事件
  const event = this.convertTaskToEvent(task)
  // 调用api添加任务
  fullCalendar.addEvent(event)
}

应用系统

名称:遇见
地址:https://meet.popsoft.tech
说明:基于一二三应用开发平台和FullCalendar日历组件实现的面向个人的时间管理、任务管理系统,1分钟注册,完整功能,欢迎使用~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学海无涯,行者无疆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值