更多推荐阅读:
前端性能&异常分析排查流程-CSDN博客
使用pycharm社区版调试DIFY后端python代码_dify后端代码怎么跑起来-CSDN博客
目录
this.$refs.fullCalendarRef.getApi().changeView('dayGridWeek')单元格中的事件相关
基础概念
FullCalendar是一个JavaScript事件日历库,它可以帮助您轻松地创建交互式日历,简称日历视图。
FullCalendar有很多用法,以下是一些常见的用法:
- 显示日历视图:FullCalendar可以显示日历视图,包括月视图、周视图和日视图等。
- 显示事件:FullCalendar可以显示事件,包括单个事件和重复事件等。
- 选择日期和时间:FullCalendar可以让用户选择日期和时间,包括单个日期和时间范围等。
- 拖放事件:FullCalendar可以让用户拖放事件,包括移动事件和调整事件持续时间等。
- 自定义样式:FullCalendar可以自定义样式,包括更改颜色、字体、大小等。
注意事项
由于他的一些步骤都是操作HTML,所以需要对原生js或jq有比较熟练的掌握。
官网地址
前期准备
安装依赖
以vue2为例子(vue3版本需要将@fullcalendar/vue 替换成@fullcalendar/vue3)
需要什么就引入什么
Plugin Index - Docs | FullCalendar
npm install @fullcalendar/core @fullcalendar/vue @fullcalendar/daygrid @fullcalendar/timegrid @fullcalendar/list @fullcalendar/interaction
由于fullcalendar的每一个功能都是一个依赖,所以如果想使用对应功能,就需要将对应的依赖进行安装
简单demo
<template>
<FullCalendar :options="calendarOptions" />
</template>
<script>
import FullCalendar from '@fullcalendar/vue'
import dayGridPlugin from '@fullcalendar/daygrid'
import interactionPlugin from '@fullcalendar/interaction'
export default {
components: {
FullCalendar // make the <FullCalendar> tag available
},
data() {
return {
calendarOptions: {
plugins: [ dayGridPlugin, interactionPlugin ],
initialView: 'dayGridMonth'
}
}
}
}
</script>
初始化配置介绍
这里指的是calendarOptions里的配置,由于有太多配置项,主要举例一些常用的说明
配置
{
// 插件,需要什么日历视图,就需要引入什么插件
plugins: [dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin],
// 高度 等同于css
height: 'calc(100% - 53px)',
// 按钮文本
buttonText: {
today: '今天',
month: '月',
week: '周',
day: '日',
list: '周列表',
},
// 自定义按钮
customButtons: {
createEventButton: {
text: '创建日程',
click: () => {
// do something
}
}
},
// 周数,第几周第几周
weekNumbers: true,
// 头部工具
headerToolbar: false,
// 当前的视图类型
initialView: this.calendarMode,
// 头部日期设置
datesSet: (info) => {
// do something
},
// 周数格式化
weekNumberFormat: { week: 'numeric' },
// 视图自定义
views: {
dayGrid: {
dayCellContent: customize.dayCellContent,
dayHeaderContent: customize.dayHeaderContent,
weekNumberContent: customize.weekNumberContent,
dayMaxEvents: 3,
duration: { weeks: 2 },
},
timeGrid: {
dayCellContent: customize.dayCellContent,
allDayContent: customize.allDayContent,
dayHeaderContent: customize.dayHeaderContent,
dayMaxEventRows: 3,
// eventMaxStack: 2,
nowIndicator: true,
nowIndicatorContent: customize.nowIndicatorContent,
// slotLabelDidMount: customize.slotLabelDidMount,
slotDuration: '01:00',
slotEventOverlap: false,
slotLabelContent: customize.slotLabelContent,
slotLabelFormat: {
hour12: false,
hour: '2-digit',
minute: '2-digit'
}
}
},
// 是否可选择
selectable: true,
//
unselectAuto: false,
// 周
weekends: true,
// 文本本地化设置
locale: 'zh-cn',
// 日期点击回调
dateClick: this.handleDateClick,
// 日期选择回调
select: this.handleDateSelect,
// 用于在每个格子里的数据,简称事件数据
events: this.eventList,
// 事件数据的点击事件
eventClick: (info) => {
// do something
},
// 事件数据的数量
eventContent: customize.eventContent,
//
eventOrderStrict: true,
//
eventOrder: (prev, next) => (prev.INDEX <= next.INDEX ? -1 : 1),
// 事件数据的格式化
eventTimeFormat: {
hour12: false,
hour: '2-digit',
minute: '2-digit'
},
// 事件超出一定数量后的显示的更多,点击更多后的触发事件
moreLinkClick: (info)=> {
// do something
},
// 更多展示的样子
moreLinkContent: customize.moreLinkContent,
}
配置详解
plugin
<template>
<FullCalendar :options="calendarOptions" />
</template>
<script>
import FullCalendar from '@fullcalendar/vue'
import dayGridPlugin from '@fullcalendar/daygrid'
import interactionPlugin from '@fullcalendar/interaction'
import timeGridPlugin from '@fullcalendar/timegrid'
import listPlugin from '@fullcalendar/list'
export default {
name: 'demo2',
components: {
FullCalendar
},
data() {
return {
calendarOptions: {
// 日布局视图插件,时间线布局视图插件,列表视图插件, 点击相关的插件
plugins: [dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin],
// 当前选中的视图
initialView: 'dayGridMonth',
// 按钮文本
buttonText: {
today: '今天',
month: '月',
week: '周',
day: '日',
list: '周列表',
},
headerToolbar: {
left: 'today prev title next',
right: 'timeGridDay,timeGridWeek,dayGridMonth,listMonth createEventButton'
},
customButtons: {
createEventButton: {
text: '创建日程',
click: () => {
console.log('do something')
}
}
},
}
}
}
}
</script>
timeGridDay视图
timeGridWeek视图
dayGridMonth视图
listMonth视图
没有数据的话,这个视图是空视图
从上面可以看出,我们的视图,是由对应视图插件,加上展示条件进行共同配置的
- dayGrid(Day/Week/Month/Year) DayGrid View - Docs | FullCalendar
- timeGrid(Day/Week) TimeGrid View - Docs | FullCalendar
- list(Day/Week/Month/Year) List View - Docs | FullCalendar
部分API
使用方式以当前的日历视图实例.getApi()去获取整个日历视图的相关数据,返回的是一个Calendar的类型
this.$refs.fullCalendarRef.getApi()
由于返回的是Calendar,所以可以直接使用Calendar下面的方法,如
this.$refs.fullCalendarRef.getApi().prev()
获取日历视图的时间显示
周视图
月视图
日视图
this.dateTitle = this.$refs.fullCalendarRef.getApi().view.title // 返回 2023年5月21日 – 6月3日关于view的参数说明
View Object - Docs | FullCalendar
日历操作相关API
日历相关的api目前用得多的还是关于calendar的
Date Navigation - Docs | FullCalendar
根据视图模式切换日期
// 往前 this.$refs.fullCalendarRef.getApi().prev() // 往后 this.$refs.fullCalendarRef.getApi().next()
切换当前视图
切换名称参考配置详解
this.$refs.fullCalendarRef.getApi().changeView('dayGridWeek')单元格中的事件相关
单元格中一条条的事项,在fullCalendar中,称为Event
Event也是有对应操作属性的
event数据结构
const eventList = [
{
// 是否是整天,如果在时间视图中,会从00:00拉到23:59
allDay: false,
// 内容的标题,显示的文本内容
title: '我的任务',
// 开始时间
start: 1684080000000,
// 结束时间
end: 1684080000000,
// 可以定义你自己的参数,点击时可以拿到该属性
extendedProps: {
a: 1,
b: 2
},
// 颜色,包含backgroundColor/borderColor,可传#f00, #ff0000, rgb(255,0,0), or red
color: 'red',
backgroundColor: 'red'.
borderColor: 'red',
textColor: 'red',
// 是否可编辑
editable: false
// 其他属性,暂时没有用到过,详情请看文档
...
}
]
详情请看文档
Event Parsing - Docs | FullCalendar
event的相关方法
除了curd
可看文档,这里不做赘述
event的点击事件
// 初始化
init() {
this.calendarOptions = {
//...
// event数组,用于存所有event
events: this.eventList,
// event的点击事件
eventClick: (info) => {
console.log(info.event.extendedProps)
// do something
},
// 自定义event样式
eventContent: null,
// 使用event的排序
eventOrderStrict: true,
// event的排序序号
eventOrder: (prev, next) => (prev.INDEX <= next.INDEX ? -1 : 1),
// event的时间格式化
eventTimeFormat: {
hour12: false,
hour: '2-digit',
minute: '2-digit'
},
}
},
自定义样式
原始demo样子
方式1:CSS方式
通过复写原始demo中的样式,达到修改的目的
方式2:在初始化视图的时候,使用自己定义的内容
对应得content进行重写其html,即可达到自定义内容的形式
// 初始化
init() {
//...
this.calendarOptions = {
// 对对应的视图进行配置,对其content进行重写,即可达到自定义内容的形式
views: {
dayGrid: {
// 每天单元格的内容
dayCellContent: (arg) => {
const { date, isToday } = arg
const year = date.getFullYear()
const month = date.getMonth()
const day = date.getDate()
const week = date.getDay()
const isFirstDayOfMonth = day === 1
const cellEl = document.createElement('div')
cellEl.className = 'cell_text'
const solarText = document.createElement('span')
const lunarText = document.createElement('span')
const weekText = document.createElement('span')
solarText.className = isFirstDayOfMonth ? 'solar_text solar_text-month' : 'solar_text'
lunarText.className = 'lunar_text'
weekText.className = 'week_text'
if (isToday) {
solarText.innerText = '今'
} else {
solarText.innerText = isFirstDayOfMonth ? `${month + 1}月` : `${day}`
}
lunarText.innerText = getLunarText(year, month, day)
weekText.innerText = `周${weekMap[week]}`
cellEl.appendChild(solarText)
cellEl.appendChild(lunarText)
cellEl.appendChild(weekText)
return {
domNodes: [cellEl]
}
},
// 每天的单元格头部内容
dayHeaderContent: (arg) => {
const { date, isToday, text } = arg
const year = date.getFullYear()
const month = date.getMonth()
const day = date.getDate()
const cellEl = document.createElement('div')
const weekEl = document.createElement('div')
const dateEl = document.createElement('div')
const solarText = document.createElement('span')
const lunarText = document.createElement('span')
cellEl.className = 'cell_text'
weekEl.className = 'week_text'
solarText.className = 'solar_text'
lunarText.className = 'lunar_text'
weekEl.innerText = text.substr(-2, 3)
solarText.innerText = isToday ? '今' : day
lunarText.innerText = getLunarText(year, month, day)
dateEl.appendChild(solarText)
dateEl.appendChild(lunarText)
cellEl.appendChild(dateEl)
return {
domNodes: [weekEl, cellEl]
}
},
// 周数的内容
weekNumberContent: (arg) => {
const weekDom = document.createElement('span')
weekDom.className = "weekNumber_text"
weekDom.innerHTML = `第${arg.text}周`
return {
domNodes: [weekDom]
}
},
// 最大显示event的条数,超出会显示more
dayMaxEvents: 10,
// 可配置时间区间的跨度,这里是显示两周
duration: { weeks: 2 },
}
},
// 自定义event样式
eventContent: (arg) => {
let { timeText, event, view } = arg
timeText = timeText || '全天'
const { allDay: isAllDay, title, extendedProps } = event
const isPast = new Date().getTime() > extendedProps.endTime
const isTimeGridWeek = view.type === 'timeGridWeek'
const duration = extendedProps.endTime - extendedProps.startTime
let isPlaceTimetext = false
let weekGridItem = `<p>${title}</p>`
if (duration >= 45 * 60 * 1000) {
if (extendedProps.place) {
weekGridItem += `<p>${extendedProps.place}</p>`
isPlaceTimetext = false
} else {
weekGridItem += `<p>${timeText}</p>`
isPlaceTimetext = true
}
if (duration >= 60 * 60 * 1000 && !isPlaceTimetext) {
weekGridItem += `<p>${timeText || '00:00-24:00'}</p>`
}
}
const isWholeDay = isAllDay || duration >= 24 * 60 * 60 * 1000
let opacity = isPast || extendedProps.status === -1 ? 0.3 : 1
const style = isTimeGridWeek ? `border-left-color: rgba(${extendedProps.color}, ${opacity})` : `background-color: rgba(${extendedProps.color}, 1)`
let withDot = isTimeGridWeek ? '' : `<span class="dot" style="background-color: rgba(${extendedProps.color}, ${opacity})"></span>`
const backgroundColor = isWholeDay ? `<div class="custom_event_background" style="${style}"></div>` : ''
let content = isTimeGridWeek ? weekGridItem : `${backgroundColor}${withDot}<span class="width_32">${timeText}</span><span class="center">${title}</span>`
let className = isTimeGridWeek ? 'in_week' : 'in_month with_dot'
const timeRangeClass = isWholeDay ? 'custom_event_content cec_long' : 'custom_event_content cec_short'
if (isPast) {
className += ' in_past'
}
if (extendedProps.status === -1) {
className += ' is_reject'
}
if (isAllDay) {
content = `<div class="custom_event_background" style="${style}"></div>${withDot}<span class="width_32">全天</span><span class="center">${title}</span>`
}
return {
html: `<div class="${timeRangeClass} ${className} calendar_ellipsis" style="cursor: pointer;${isTimeGridWeek ? style : ''}" title="${title}">${content}</div>`
}
},
// 更多点击的样式
moreLinkContent: (arg) => {
const { num } = arg
return `还有${num}个日程或任务`
},
}
},
结果
方式3: 自定义视图plugin
注意:除非确认所有视图都不能使用,才使用这种视图,文档上描述不是很清晰,并不能让我们知道自定义后事件是如何触发的,很多东西都要重新写过,事件触发还得自己搞
如实现以下这种视图
官方文档
Custom Views via JS - Docs | FullCalendar
定义一个plugin.js
他需要以
createPlugin({
views: {
// 自定义视图的名称,切换视图时使用的就是该视图名称
customWeek: customWeekViewConfig
}
})
的形式导出
import { sliceEvents, createPlugin } from '@fullcalendar/core';
import dayjs from 'dayjs';
import $ from 'jquery'
const weekCn = ['日','一','二','三','四','五','六']
// 获取日期区间
function getDateList({start}) {
if(!start) {
return []
}
const arr = [];
for (let i = 0; i < 7; i++) {
const t = new Date(start);
t.setDate(start.getDate() + i);
arr.push({
year: t.getFullYear(),
month: t.getMonth() + 1,
date: t.getDate()
});
}
return arr
}
// 获取事件列表
function getEventMap(events) {
const eventMap = {}
events.forEach(item => {
const date = item.range.start.getDate()
if(!eventMap[date]) {
eventMap[date] = []
}
eventMap[date].push(item)
})
return eventMap
}
// 获取每一天的事件
function getEventToHTML(event, date) {
if(!event) {
return ''
}
let html = ''
for(let i=0; i<event.length;i++) {
const item = event[i]
const startTime = dayjs(item.def.extendedProps.startTime)
const endTime = dayjs(item.def.extendedProps.endTime)
const isAllDay = item.def.extendedProps.isAllDay || !startTime.isSame(endTime, 'day') || endTime.isAfter(startTime, 'day')
const isMorning = Number(startTime.format('H')) < 12 && Number(endTime.format('H')) < 12
html += `
<div class="eventItem${isAllDay? ' isAllDay': ''}${!isAllDay && !isMorning? ' isAfternoon': ''}" data-id="${item.def.extendedProps.id}" data-date="${date}">
${startTime.format(isAllDay ? 'MM-DD HH:mm' : 'HH:mm:ss')}${isAllDay?'至':'-'}${endTime.isValid() ? endTime.format(isAllDay ? 'MM-DD HH:mm' : 'HH:mm:ss'):'--:--'} ${item.def.title}
</div>
`
if(i===2 && event.length - 3 > 0) {
html += `<div class="eventItem-more" data-id="${item.def.extendedProps.id}" data-date="${startTime.format('YYYY-MM-DD')}">还有${event.length - 3}个日程或任务</div>`
break;
}
}
return html
}
// 获取一周HTML
function getWeekListHTML(currentRange, events) {
window.dateList = getDateList(currentRange)
let listString = ''
const nowDay = new Date().getDate()
const eventMap = getEventMap(events)
weekCn.forEach((item,index) => {
const date = window.dateList[index].date
listString+=`
<div class="weekItem">
<div
class="weekDate"
${nowDay === date ? 'style="color:#0085FF"': ""}>
<span>${date}</span>
<br/>
<span>周${item}</span>
</div>
<div class="weekNote view-events">
${getEventToHTML(eventMap[date], date)}
</div>
</div>`
})
return listString
}
// 自定义周视图配置
const customWeekViewConfig = {
classNames: [ 'custom-view' ],
content: function(props) {
// 事件
let segs = sliceEvents(props, true); // allDay=true
const segsMap = {}
segs.forEach(item => {
const id = item.def.extendedProps.id
segsMap[id] = item.def
})
let html =`
<div class="customWeekView">
<div class="header view-title">
<div>上午</div>
<div>下午</div>
</div>
<div class="weekList">
${getWeekListHTML(props.dateProfile.currentRange, segs)}
</div>
</div>
`
// 监听事件
$(document).off('click', '.eventItem');
$(document).on('click', '.eventItem', function() {
const id = $(this).data('id')
console.log(segsMap[id])
if(id) {
// 调用日历视图实例上的event点击事件
document.querySelector('.pc_calendar_content').__vue__._data.calendarOptions.eventClick({event: segsMap[id]})
}
})
$(document).off('click', '.eventItem-more');
$(document).on('click', '.eventItem-more', function() {
const date = $(this).data('date')
if(date) {
// 调用日历视图实例上的更多点击事件
document.querySelector('.pc_calendar_content').__vue__.showMoreFunction({date})
}
})
return { html }
},
}
// 最终输出给calendar的配置使用
const plugin = createPlugin({
views: {
// 自定义视图的名称
customWeek: customWeekViewConfig
}
});
export default plugin
plugin在calendar的初始化配置里使用
<template>
<div class="pc_calendar_content">
<div class="pc_calendar">
<FullCalendar
v-loading="isLoading"
ref="fullCalendarRef" :options="calendarOptions" >
<template #eventContent="{ event }">
<span>{{ event.allDay ? '全天' : event.start }}</span>
<span>{{ event.title }}</span>
</template>
</FullCalendar>
</div>
<van-overlay :show="showMore" @click="showMore = false">
<div class="calendar_wrapper">
<div class="more_calendar_content" @click.stop>
<div class="more_title">{{showMoreDate}}</div>
<div class="more_list">
<div
class="calendar_search_item_content"
v-for="item2 in showMoreEvents" :key="item2.id"
@click="handleClickEvent(item2)">
<div class="calendar_search_item_title">
<div style="width: 160px">{{ item2.calendarName }}</div>
<div>{{ item2.startTime }}</div>
</div>
<div class="calendar_search_item_footer">
<div style="width: 160px">组织人:{{ item2.organizer || '-' }}</div>
<div>{{ item2.endTime }}</div>
</div>
</div>
</div>
</div>
</div>
</van-overlay>
</div>
</template>
<script>
import FullCalendar from '@fullcalendar/vue'
import customWeekPlugin from './utils/customWeekViewPlugin'
export default {
data() {
return {
showMore: false,
showMoreEvents: [],
showMoreDate: ''
}
},
methods: {
// 初始化
init() {
this.calendarOptions = {
// 使用自定义视图
plugins: [customWeekPlugin],
// 切换到该视图对应的名称,与视图plugin中的视图名称一致
initialView: 'customWeek',
eventClick: ()=>{},
views: {
// 视图的配置
customWeek: {
duration: { weeks: 1 }
}
}
}
},
// 自己定义的点击打开更多
showMoreFunction(data) {
this.showMore = true
this.showMoreEvents = []
this.showMoreDate = `${dayjs(data.date).format('M月D日')} 星期${weekMap[dayjs(data.date).day()]}`
this.eventList.forEach(dItem => {
const dateItem = JSON.parse(JSON.stringify(dItem.extendedProps))
if(dayjs(dateItem.startTime).format('YYYY-MM-DD') === data.date){
const {
startTime,
endTime,
isAllDay
} = dateItem
const start = dayjs(startTime)
const end = dayjs(endTime)
const allDay = isAllDay || !start.isSame(end, 'day') || end.isAfter(start, 'day')
dateItem.startTime = startTime ? `${start.format(allDay ? 'MM月DD日 HH:mm:ss' : 'HH:mm:ss')}` : '-'
dateItem.endTime = endTime ? `${end.format(allDay ? 'MM月DD日 HH:mm:ss' : 'HH:mm:ss')}` : '-'
this.showMoreEvents.push(dateItem)
}
})
}
}
}
</script>
这样一个自定义plugin就完成了
七巧低代码是以业务应用搭建为核心的aPaaS低代码应用平台,为客户提供aPaaS+iPaaS的全民数智化解决方案。技术资料获取