具体实现效果图如图所有:
1、安装FullCalendar相关插件
npm install --save "@fullcalendar/core"
npm install --save "@fullcalendar/interaction"
npm install --save "@fullcalendar/daygrid"
npm install --save "@fullcalendar/vue"
2、引用,静态数据进行拖拽(此时没有请求任何接口)
<FullCalendar ref="fullCalendar" :options="calendarOptions"/>
import '@fullcalendar/core/vdom' // solves problem with Vite
import FullCalendar from '@fullcalendar/vue'
import dayGridPlugin from '@fullcalendar/daygrid'
import interactionPlugin, { Draggable } from '@fullcalendar/interaction'
export default {
name: 'TradingTimeManage',
components: {
FullCalendar
},
data() {
return {
eventEl: null,
calendarOptions: { //?拖拽日历配置
plugins: [dayGridPlugin, interactionPlugin],
firstDay: 1, // 把每周设置为从周一开始
header: { // 日历头部
left: 'prev,next today',
center: 'title',
right: 'custom'
},
/* 设置按钮文字 */
buttonText:{
today:'今天',
},
initialView: 'dayGridMonth',
locale: 'zh-cn', //? 配置中文
selectable: true,//可编辑
// dayMaxEvents: true,
slotMinutes: 15,
editable: false, // 日历上是否可拖拽
droppable: true,
dropAccept: '.list-group-item',
drop: this.drop,
},
events: []
},
list: [
{ name: '工作日', value: '1', color: 'green' },
{ name: '春节放假', value: '7', color: 'blue' },
{ name: '中秋节放假', value: '3', color: 'blue' },
{ name: '国庆节放假', value: '7', color: 'blue' },
{ name: '游玩', value: '7', color: 'blue' },
]
}
},
mounted() {
var containerEl = document.getElementById('list-group-item');
// 初始化外部事件
new Draggable(containerEl, {
itemSelector: '.list-group-item',
}
)
},
methods: {
drop(date, allDay) {
this.calendarOptions.events.push({ // add new event data
title: date.draggedEl.firstChild.innerHTML,
start: date.dateStr,
end: moment(date.dateStr).add(date.draggedEl.lastChild.innerHTML, 'days').format('YYYY-MM-DD')
})
}
}
}
3、 获取当前日历视图开始时间、结束时间
// 获取当前视图日历的范围
const time = this.$refs.fullCalendar.getApi().currentDataManager.state.dateProfile.renderRange
this.start = Date.parse(moment(time.start).format()) // 视图开始时间
this.end = Date.parse(moment(time.end).format()) // 视图结束时间
4、上月、下月、今天添加事件
calendarOptions: { //?拖拽日历配置
customButtons: {
prev: {
// this overrides the prev button
text: "PREV",
click: () => {
this.prevMethod();
},
},
next: {
// this overrides the next button
text: "PREV",
click: () => {
this.nextMethod();
},
},
today: {
text: "今天",
click: () => {
this.todayMethod();
},
},
},
},
/** 上个月 */
prevMethod() {
this.$refs.fullCalendar.getApi().prev() // 更新上个月视图
console.log(this.$refs.fullCalendar.getApi().currentDataManager.state.dateProfile.renderRange)
},
/** 下个月 */
nextMethod() {
this.$refs.fullCalendar.getApi().next() // 更新下个月视图
console.log(this.$refs.fullCalendar.getApi().currentDataManager.state.dateProfile.renderRange)
},
/** 今天 */
todayMethod() {
this.$refs.fullCalendar.getApi().today() // 更新今天视图
console.log(this.$refs.fullCalendar.getApi().currentDataManager.state.dateProfile.renderRange)
},
5、 请求接口,动态回显日历活动方法
/** 获取视图活动数据方法 */
holidayEvent(){
// 获取当前视图日历的范围
const time = this.$refs.fullCalendar.getApi().currentDataManager.state.dateProfile.renderRange
this.start = Date.parse(moment(time.start).format()) // 视图开始时间
this.end = Date.parse(moment(time.end).format()) // 视图结束时间
// 从接口获取数据,更新日历视图活动
holidayItem({ start: this.start, end: this.end }).then((res)=> {
if (res.status === '200') {
const data = res.data
const arr = []
data.forEach(item => {
const obj = {
id: item.id,
title: item.name,
start: item.day,
end: item.dayEnd,
allDay: true,
backgroundColor: item.name === '工作日' ? 'green' : '#3788d8'
}
arr.push(obj)
})
this.calendarOptions.events = arr
}
})
},
7、完整的拖动日历代码(包含请求接口)
<!--交易时间管理 -->
<template>
<div class="container">
<el-row :gutter="30">
<el-col :span="8">
<div class="module-title">假期列表</div>
<div class="date-box" id="list-group-item">
<div class="flex-b box list-group-item" v-for="item in list" :key="item.name">
<div>{{ item.name }}</div>
<div class="circle" :class="item.color">{{ item.value }}</div>
</div>
</div>
</el-col>
<el-col :span="16">
<FullCalendar ref="fullCalendar" :options="calendarOptions"/>
</el-col>
</el-row>
</div>
</template>
<script>
import { holidayItem, holidayAdd } from '@/api/methodsApi' // 项目中接口文件引入
import * as moment from 'moment'
import '@fullcalendar/core/vdom' // solves problem with Vite
import FullCalendar from '@fullcalendar/vue'
import dayGridPlugin from '@fullcalendar/daygrid'
import interactionPlugin, { Draggable } from '@fullcalendar/interaction'
export default {
name: 'TradingTimeManage',
components: {
FullCalendar
},
data() {
return {
eventEl: null,
calendarOptions: { //?拖拽日历配置
plugins: [dayGridPlugin, interactionPlugin],
firstDay: 1, // 把每周设置为从周一开始
header: { // 日历头部
left: 'prev,next today',
center: 'title',
right: 'custom'
},
/* 设置按钮文字 */
buttonText:{
today:'今天',
},
initialView: 'dayGridMonth',
locale: 'zh-cn', //? 配置中文
selectable: true,//可编辑
// dayMaxEvents: true,
slotMinutes: 15,
editable: false, // 日历上是否可拖拽
droppable: true,
dropAccept: '.list-group-item',
drop: this.drop,
customButtons: {
prev: {
// this overrides the prev button
text: "PREV",
click: () => {
this.prevMethod();
},
},
next: {
// this overrides the next button
text: "PREV",
click: () => {
this.nextMethod();
},
},
today: {
text: "今天",
click: () => {
this.todayMethod();
},
},
},
events: []
},
start: null,
end: null,
calendarEvents: [],
list: [
// { name: '删除假日', value: '0', color: 'blue' }
{ name: '工作日', value: '1', color: 'green' },
{ name: '春节放假', value: '7', color: 'blue' },
{ name: '中秋节放假', value: '3', color: 'blue' },
{ name: '国庆节放假', value: '7', color: 'blue' },
{ name: '游玩', value: '7', color: 'blue' },
]
}
},
mounted() {
var containerEl = document.getElementById('list-group-item');
// 初始化外部事件
new Draggable(containerEl, {
itemSelector: '.list-group-item',
}
)
this.holidayEvent() // 调用获取视图活动数据方法
},
methods: {
/** 上个月 */
prevMethod() {
this.$refs.fullCalendar.getApi().prev() // 更新上个月视图
this.holidayEvent() // 调用获取视图活动数据方法
},
/** 下个月 */
nextMethod() {
this.$refs.fullCalendar.getApi().next() // 更新下个月视图
this.holidayEvent() // 调用获取视图活动数据方法
},
/** 今天 */
todayMethod() {
this.$refs.fullCalendar.getApi().today() // 更新今天视图
this.holidayEvent() // 调用获取视图活动数据方法
},
/** 获取视图活动数据方法 */
holidayEvent(){
// 获取当前视图日历的范围
const time = this.$refs.fullCalendar.getApi().currentDataManager.state.dateProfile.renderRange
this.start = Date.parse(moment(time.start).format()) // 视图开始时间
this.end = Date.parse(moment(time.end).format()) // 视图结束时间
// 从接口获取数据,更新日历视图活动
holidayItem({ start: this.start, end: this.end }).then((res)=> {
if (res.status === '200') {
const data = res.data
const arr = []
data.forEach(item => {
const obj = {
id: item.id,
title: item.name,
start: item.day,
end: item.dayEnd,
allDay: true,
backgroundColor: item.name === '工作日' ? 'green' : '#3788d8'
}
arr.push(obj)
})
this.calendarOptions.events = arr
}
})
},
drop(date, allDay) {
let typeNumber = null
const firstChildName = null
const obj = {
name: date.draggedEl.firstChild.innerHTML,
day:Date.parse(moment(date.dateStr).format()), // 开始时间
dayEnd: Date.parse(moment(date.dateStr).add(date.draggedEl.lastChild.innerHTML, 'days').format()), // 结束时间
dayNum: date.draggedEl.lastChild.innerHTML,
}
// 拖拽后,新增日历活动接口调用
holidayAdd(obj).then(res=>{
if(res.status === '200') {
console.log(res, 'data')
const data = res.data
this.holidayEvent() // 调用获取视图活动数据方法
}
})
}
}
}
</script>
<style lang="scss" scoped>
.circle {
background-color: #3788d8;
border-radius: 10px;
color: #fff;
display: inline-block;
font-size: 12px;
height: 18px;
line-height: 18px;
padding: 0 6px;
text-align: center;
white-space: nowrap;
border: 1px solid #fff;
}
.blue {
background-color: #3788d8;
}
.green{
background-color: green;
}
.date-box {
//border: 1px solid #ccc;
border-radius: 5px;
}
.box {
margin-top:15px;
border: 1px solid #ccc;
padding: 10px 20px;
border-radius: 5px;
}
.is-selected {
color: #1989FA;
}
</style>
注意:不要在eventsSet: this.handleEvents
这个方法中去操作this.calendarOptions.events数据。如果在handleEvents方法中去请求接口,或者赋值,会导致视图一直刷新,进入死循环。