fullCalendar日歷插件玩法解析


fullCalendar日歷

  1、在用之前我先介紹為啥要用這個fullcalendar日歷插件,首先我在用之前是用的Ant Design of Vue框架的日歷,這個框架的日歷就比較單調沒有很靈活的能操作日歷里面的日歷日程,而fullcalendar日歷就能很靈活的進行日歷方面的操作。

  2、在剛開始用的時候還是有太多坑的,fullCalendar日歷插件在我現在發現的有(vue-full-calendar 、vue-fullcalendar 、 calendar),凡是看到npm install以上三個的就不要去下載了,雖然vue-fullcalendar是可以使用的,但想要使用下載fullCalendar里面的其它包是不可以的。

Fullcalendar安裝

  • 安裝所需要的npm包
    npm install --save @fullcalendar/vue 
    下面包是日歷的周視圖、日視圖等插件包:
    npm install --save @fullcalendar/core @fullcalendar/daygrid @fullcalendar/interaction @fullcalendar/list @fullcalendar/timegrid

    安裝后的fullcalendar源碼和其它插件都會在@fullcalendar

     

  • 導入HTML
    <template>
      <div>
          <FullCalendar ref="myCalendar" :options="calendarOptions"/>
      </div>
    </template>

     

  • 導入JS
    import FullCalendar from '@fullcalendar/vue'
    import dayGridPlugin from '@fullcalendar/daygrid'
    import timeGridPlugin from '@fullcalendar/timegrid'
    import interactionPlugin from '@fullcalendar/interaction'
    import listPlugin from '@fullcalendar/list'

     

    復制代碼
    export default {
      name: 'MaintenanceCalendarview',
      components: {
        FullCalendar
      },
      data () {
        return {
          calendarOptions: {
            // 引入的插件,比如fullcalendar/daygrid,fullcalendar/timegrid引入后才可顯示月,周,日
            plugins: [ dayGridPlugin, interactionPlugin, timeGridPlugin, listPlugin ],
            initialView: 'dayGridMonth', // 默認為那個視圖(月:dayGridMonth,周:timeGridWeek,日:timeGridDay)
            firstDay: 1, // 設置一周中顯示的第一天是哪天,周日是0,周一是1,類推
            locale: 'zh-cn', // 切換語言,當前為中文
            eventColor: '#3BB2E3', // 全部日歷日程背景色
            themeSystem: 'bootstrap', // 主題色(本地測試未能生效)
            initialDate: moment().format('YYYY-MM-DD'), // 自定義設置背景顏色時一定要初始化日期時間
            timeGridEventMinHeight: '20', // 設置事件的最小高度
            aspectRatio: 1.65, // 設置日歷單元格寬度與高度的比例。
            // displayEventTime: false, // 是否顯示時間
            // allDaySlot: false, // 周,日視圖時,all-day 不顯示
            eventLimit: true, // 設置月日程,與all-day slot的最大顯示數量,超過的通過彈窗顯示
            headerToolbar: { // 日歷頭部按鈕位置
              left: '',
              center: 'prevYear,prev title next,nextYear',
              right: 'today dayGridMonth,timeGridWeek,timeGridDay'
            },
            buttonText: {
              today: '今天',
              month: '月',
              week: '周',
              day: '日'
            },
            slotLabelFormat: {
              hour: '2-digit',
              minute: '2-digit',
              meridiem: false,
              hour12: false // 設置時間為24小時
            },
            eventLimitNum: { // 事件顯示數量限制(本地測試未能生效)
              dayGrid: {
                eventLimit: 5
              },
              timeGrid: {
                eventLimit: 2 // adjust to 6 only for timeGridWeek/timeGridDay
              }
            },
            // 事件
            // eventClick: this.handleEventClick, // 點擊日歷日程事件
            eventDblClick: this.handleEventDblClick, // 雙擊日歷日程事件 (這部分是在源碼中添加的)
            eventClickDelete: this.eventClickDelete, // 點擊刪除標簽事件 (這部分是在源碼中添加的)
            eventDrop: this.eventDrop, // 拖動日歷日程事件
            eventResize: this.eventResize, // 修改日歷日程大小事件
            select: this.handleDateSelect, // 選中日歷格事件
            eventDidMount: this.eventDidMount, // 安裝提示事件
            // loading: this.loadingEvent, // 視圖數據加載中、加載完成觸發(用於配合顯示/隱藏加載指示器。)
            // selectAllow: this.selectAllow, //編程控制用戶可以選擇的地方,返回true則表示可選擇,false表示不可選擇
            eventMouseEnter: this.eventMouseEnter, // 鼠標滑過
            allowContextMenu: false,
            editable: true, // 是否可以進行(拖動、縮放)修改
            eventStartEditable: true, // Event日程開始時間可以改變,默認true,如果是false其實就是指日程塊不能隨意拖動,只能上下拉伸改變他的endTime
            eventDurationEditable: true, // Event日程的開始結束時間距離是否可以改變,默認true,如果是false則表示開始結束時間范圍不能拉伸,只能拖拽
            selectable: true, // 是否可以選中日歷格
            selectMirror: true,
            selectMinDistance: 0, // 選中日歷格的最小距離
            dayMaxEvents: true,
            weekends: true,
            navLinks: true, // 天鏈接
            selectHelper: false,
            slotEventOverlap: false // 相同時間段的多個日程視覺上是否允許重疊,默認true允許
          }
        }
      },
      methods: {
        eventMouseEnter (event, jsEvent, view) { // 鼠標划過的事件
          if (event.event.classNames.length) {
            // console.log(event)
          }
        },
        eventDrop (event, dayDelta, minuteDelta, allDay, revertFunc, jsEvent, ui, view) {
          console.log(event)
        }
    
      }
    }
    復制代碼

     

     (以上日歷事件以及event事件差不多這些都是我個人感覺能用到的我才加進去了)

  • event: [ ]    ==>(event能否進行操作真正取決於開始日期和結束日期的格式,即使是設置了editable,時間還是會影響 ,一共有四種情況,當日期時間為00:00到23:59時為全天)  
    復制代碼
        events: [
          {
            title : '可以拖動但不能縮放',
            start : '2019-07-01 12:30',
            end : '2019-07-01 13:30',
       editable: true },//可以拖動但不能縮放,但在周、日視圖中是可以進行縮放的 { title : '可以拖動、縮放', start : '2019-07-02 00:00', end : '2019-07-02 23:59', color:'red',
    editable: true }, //可以拖動、縮放
         {
            title : 'event 2',
            start : '2019-07-02',
            end : '2019-07-02',
            color:'red',
    editable: true },
      { title: 'event 1', date: '2020-06-01', classNames:['cal'],
    editable: true }, { start: '2020-07-24', end: '2020-07-28', overlap: false, display: 'background', color: '#ff9f89' },//背景色 (添加相同時間的背景色時顏色會重疊) 一點要初始化日期時間 initialDate: '2020-07-10', ],
    復制代碼

     

  • 添加約束(日程只能在設置了 groupId: 'availableForMonthStart' 中進行拖動以及縮放功能)
    復制代碼
    { 
            id: '添加約束',
            title: '添加約束',
            start: '2020-07-11 00:00',
            end: '2020-07-11 12:00',
            classNames: ['continuousClass'],
            color: '#75a7c8',
            editable: true,
            constraint: 'availableForMonthStart'
          },
          {
            id: 'constraintDom',
            groupId: 'availableForMonthStart',
            start: '2020-07-11 00:00',
            end: '2020-07-11 23:59',
            display: 'background',
            color: '#ff9f89'
          }
    復制代碼

     

自定義事件方法(dblClick)

  在日歷事件方法看來難免還是會缺少部分方法的

  這里我在日歷源碼中根據原先的點擊方法中復制了一個雙擊事件:

  

   

 

(這里根據原先的點擊事件添加dblclick就可以了)

復制代碼
// 添加雙擊事件
var EventDblClicking = /** @class */ (function (_super) {
    __extends(EventDblClicking, _super);
    function EventDblClicking(settings) {
        var _this = _super.call(this, settings) || this;
        _this.handleSegClick = function (ev, segEl) {
            var component = _this.component;
            var context = component.context;
            var seg = getElSeg(segEl);
            if (seg && // might be the <div> surrounding the more link
                component.isValidSegDownEl(ev.target)) {
                // our way to simulate a link dblclick for elements that can't be <a> tags
                // grab before trigger fired in case trigger trashes DOM thru rerendering
                var hasUrlContainer = elementClosest(ev.target, '.fc-event-forced-url');
                var url = hasUrlContainer ? hasUrlContainer.querySelector('a[href]').href : '';
                context.emitter.trigger('eventDblClick', {
                    el: segEl,
                    event: new EventApi(component.context, seg.eventRange.def, seg.eventRange.instance),
                    jsEvent: ev,
                    view: context.viewApi
                });
                if (url && !ev.defaultPrevented) {
                    window.location.href = url;
                }
            }
        };
        _this.destroy = listenBySelector(settings.el, 'dblclick', '.fc-event', // on both fg and bg events
        _this.handleSegClick);
        return _this;
    }
    return EventDblClicking;
}(Interaction));
復制代碼

 (自定義方法添加就這三個地方)

 

自定義刪除標簽:

  考慮到日歷日程都是遍歷出來的,想通過在遍歷中添加標簽這方法實屬麻煩

  這邊采用的方法是修改源碼內部添加刪除標簽

  (這邊添加后唯一的問題就是這個刪除標簽的樣式,因為他拖動或者縮放的時候還會有這個刪除按鈕,至於樣式處理我這邊就不詳細弄了,因為我忘了我改了啥樣式)

修改第一處(月視圖):

復制代碼
var StandardEvent = /** @class */ (function (_super) {
    __extends(StandardEvent, _super);
    function StandardEvent() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    StandardEvent.prototype.render = function () {
        var _a = this, props = _a.props, context = _a.context;
        var seg = props.seg;
        var timeFormat = context.options.eventTimeFormat || props.defaultTimeFormat;
        var timeText = buildSegTimeText(seg, timeFormat, context, props.defaultDisplayEventTime, props.defaultDisplayEventEnd);
        return (createElement(EventRoot, { seg: seg, timeText: timeText, disableDragging: props.disableDragging, disableResizing: props.disableResizing, defaultContent: props.defaultContent || renderInnerContent, isDragging: props.isDragging, isResizing: props.isResizing, isDateSelecting: props.isDateSelecting, isSelected: props.isSelected, isPast: props.isPast, isFuture: props.isFuture, isToday: props.isToday }, function (rootElRef, classNames, innerElRef, innerContent, hookProps) { return (createElement("a", __assign({ className: props.extraClassNames.concat(classNames).join(' '), style: {
                borderColor: hookProps.borderColor,
                backgroundColor: hookProps.backgroundColor
            }, ref: rootElRef }, getSegAnchorAttrs(seg)),
            // 手動添加了刪除標簽
            createElement("div", { className: 'fc-eventTooltip' }),
            createElement("a", { className: 'fc-eventDeleteClick' }, '刪除'),
            createElement("div", { className: 'fc-event-main', ref: innerElRef, style: { color: hookProps.textColor } }, innerContent,),
            
            hookProps.isStartResizable &&
                createElement("div", { className: 'fc-event-resizer fc-event-resizer-start' }),
            hookProps.isEndResizable &&
                createElement("div", { className: 'fc-event-resizer fc-event-resizer-end' },))); }));
    };
    return StandardEvent;
}(BaseComponent));
復制代碼

找到這部分代碼,然后替換掉

 

修改第二處(這部分是周、日視圖中的刪除,本來我想把刪除標簽放到日程內容下面,但周視圖中的樣式有點搞笑,會被撐下去,至於放那里,取決你們自己了):

復制代碼
// 手動添加了刪除標簽
function renderInnerContent(innerProps) {
    return (createElement(Fragment, null,
        // createElement("div", { className: 'fc-daygrid-event-dot', style: { borderColor: innerProps.borderColor || innerProps.backgroundColor } }),
        innerProps.timeText &&
        createElement("div", { className: 'fc-eventTooltip' }),
        createElement("a", { className: 'fc-eventDeleteClick' }, '刪除'),
        createElement("div", { className: 'fc-event-title' }, innerProps.event.title || createElement(Fragment, null, "\u00A0")),
            createElement("div", { className: 'fc-event-time' }, innerProps.timeText)));
}
復制代碼

(替換掉后,是沒有點擊事件的,同上方自定義點擊事件一樣自己自定義就好了,這邊提示一下:不是所有隨便一個標簽添加自定義事件都能成功的)

效果圖:

這邊我推薦幾個方法來修改樣式(這幾個方法都可以操作日程中的樣式 ):

  eventDidMount: this.eventDidMount,// 渲染時

  eventDragStart: this.eventDragStart, // 日程開始拖拽時觸發

  eventDragStop: this.eventDragStop, // 日程拖拽結束時觸發

  eventResizeStart: this.eventResizeStart, // 日程大小調整開始時觸發

  eventResizeStop: this.eventResizeStop, // 日程大小調整結束時觸發

 

日歷選中方法(這里添加了一個選中日歷格后再次點擊日歷個后新增<雙擊日歷格>):

select: this.handleDateSelect 
復制代碼
// 選中日歷格快速新增
    handleDateSelect (selectInfo) {
      console.log(selectInfo)
      console.log(selectInfo.jsEvent.timeStamp)
      // 當點擊兩次同日歷格時判斷(要第一次點擊選中之后在點擊才會生效)
      if ((moment(selectInfo.endStr).valueOf() - moment(selectInfo.startStr).valueOf() === 86400000 &&
        moment(selectInfo.startStr).valueOf() >= moment(moment().format('YYYY-MM-DD')).valueOf() &&
        selectInfo.view.type === 'dayGridMonth') ||
        ((selectInfo.view.type === 'timeGridWeek' || selectInfo.view.type === 'timeGridDay') &&
          moment(selectInfo.startStr).valueOf() >= moment(moment().format('YYYY-MM-DD')).valueOf() &&
          (selectInfo.allDay ? (moment(selectInfo.endStr).valueOf() - moment(selectInfo.startStr).valueOf() === 86400000)
            : (moment(selectInfo.end).valueOf() - moment(selectInfo.start).valueOf() > 1800000))
        )) {
        let temporaryTime = {}
        temporaryTime = {
          timeStamp: selectInfo.jsEvent.timeStamp,
          timeString: moment(selectInfo.start).format('YYYY-MM-DD')
        }
        // 第一次點擊時獲取選中
        if (this.selectTimeStamp.length === 0) {
          this.selectTimeStamp.push({
            timeStamp: selectInfo.jsEvent.timeStamp,
            timeString: moment(selectInfo.start).format('YYYY-MM-DD')
          })
        } else {
          // 第二次點擊時判斷是否和第一次一樣,不一樣就刪除第一次的,添加第二次的
          this.selectTimeStamp.forEach(item => {
            if (item.timeString === temporaryTime.timeString) {
              //內容
            } else {
              this.selectTimeStamp.splice(this.selectTimeStamp.findIndex(event => event.timeString === item.timeString), 1)
              this.selectTimeStamp.push({
                timeStamp: selectInfo.jsEvent.timeStamp,
                timeString: moment(selectInfo.start).format('YYYY-MM-DD')
              })
            }
          })
        }
      }
      // 判斷過去時間不能新增
      if ((moment(selectInfo.endStr).valueOf() - moment(selectInfo.startStr).valueOf() > 86400000 &&
        moment(selectInfo.startStr).valueOf() < moment(moment().format('YYYY-MM-DD')).valueOf() &&
        selectInfo.view.type === 'dayGridMonth') ||
        ((selectInfo.view.type === 'timeGridWeek' || selectInfo.view.type === 'timeGridDay') &&
          moment(selectInfo.startStr).valueOf() < moment(moment().format('YYYY-MM-DD')).valueOf() &&
          (selectInfo.allDay ? (moment(selectInfo.endStr).valueOf() - moment(selectInfo.startStr).valueOf() > 86400000)
            : (moment(selectInfo.end).valueOf() - moment(selectInfo.start).valueOf() > 1800000))
        )) {
        this.$confirm({
          title: '提示',
          content: '過去時間不能進行新增!',
          okText: '確定',
          cancelText: '取消',
          onOk () {
          }
        })
      }
      // 判斷獲取的時間大於當前、以及兩天以上
      if ((moment(selectInfo.endStr).valueOf() - moment(selectInfo.startStr).valueOf() > 86400000 &&
        moment(selectInfo.startStr).valueOf() >= moment(moment().format('YYYY-MM-DD')).valueOf() &&
        selectInfo.view.type === 'dayGridMonth') ||
        ((selectInfo.view.type === 'timeGridWeek' || selectInfo.view.type === 'timeGridDay') &&
          moment(selectInfo.startStr).valueOf() >= moment(moment().format('YYYY-MM-DD')).valueOf() &&
          (selectInfo.allDay ? (moment(selectInfo.endStr).valueOf() - moment(selectInfo.startStr).valueOf() > 86400000)
            : (moment(selectInfo.end).valueOf() - moment(selectInfo.start).valueOf() > 1800000))
        )) {
        //內容
      }
    },
復制代碼
 
        

 

 

 

效果圖:

 

 

 

 

這里我給到一個文檔的參考event事件鈎子:

 Events and Hooks

  • event-selected(event, jsEvent, view) - Triggered on eventClick()
  • event-mouseover(event, jsEvent, view) - Triggered on eventMouseover()
  • event-mouseout(event, jsEvent, view) - Triggered on eventMouseout()
  • event-drop(event) - Triggered on eventDrop()
  • event-resize(event) - Triggered on eventResize()
  • event-created(event) - Triggered on select()
  • event-receive(event) - Triggered on eventReceive()
  • event-render(event) - Triggered on eventRender()
  • view-render(view, element) - Triggered on viewRender()
  • day-click(date, jsEvent, view) - Triggered on dayClick()

 

擴展--------------------------------------------

1、月視圖增加農歷

calendarOptions中增加views數據;

 

通過dayCellContent來設置日期里顯示的數據;

 

引入calendar.js計算農歷 https://github.com/jjonline/calendar.js

復制代碼
import calenderFormate from "../utils/calendar" //農歷計算方法
import {formatDate} from "../utils/index" //將日期對象轉換成 2020-01-01 格式的日期
 
//data中calendarOptions修改:
calendarOptions: {
    views:{
        //對應月視圖
        dayGridMonth:{
            displayEventTime:false,//是否顯示時間
            dayCellContent(item){
              let _date=formatDate(item.date).split('-')
              let _dateF=calenderFormate.solar2lunar(_date[0],_date[1],_date[2])
              return {html:`<p><label>${_dateF.cDay}</label><span>${_dateF.IDayCn}</span></p>`}
        },
    }
   },
}
復制代碼

 

2、周視圖增加農歷

在前面的基礎上修改views;

在dayHeaderContent中設置顯示數據;

復制代碼
views: {
    //對應周視圖調整
     timeGridWeek:{
     slotMinTime:"09:00",//周視圖開始時間
     slotMaxTime:"20:00",//周視圖結束時間
     displayEventTime:false,//是否顯示時間
     dayHeaderContent(item){
         let _date=formatDate(item.date).split('-')
         let _dateF=calenderFormate.solar2lunar(_date[0],_date[1],_date[2])
         return {html:`<h3>${_dateF.ncWeek.slice(2)}</h3><p><label>${_dateF.cDay}</label><span>${_dateF.IDayCn}</span></p>`}
     }
  }
}
復制代碼

 

效果圖:

 

 

 

 

推薦參考的文檔:

https://fullcalendar.io/ 
https://www.npmjs.com/package/vue-full-calendar

https://blog.csdn.net/supingemail/article/details/48371927

(這里我提一下,一般在git提交代碼的時候,修改的源碼是不能提上去的,要手動打包過去)

(這邊我暫時就添加了我個人覺得夠用的,只是部分沒詳細解釋,我想起來的話會更新的,如果有什么問題可以在下面留言)

 全中文API翻譯:https://www.cnblogs.com/zhangruisoldier/p/7985202.html

 

轉載:https://www.cnblogs.com/czk1634798848/p/13386178.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM