PHP+mysql防止SQL注入
fullCalendar日曆
1、在用之前我先介紹為啥要用這個fullcalendar日曆外掛,首先我在用之前是用的Ant Design of Vue框架的日曆,這個框架的日曆就比較單調沒有很靈活的能操作日曆裡面的日曆日程,而fullcalendar日曆就能很靈活的進行日曆方面的操作。
2、在剛開始用的時候還是有太多坑的,fullCalendar日曆外掛在我現在發現的有(vue-full-calendar 、vue-fullcalendar 、 calendar),凡是看到npminstall以上三個的就不要去下載了,雖然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提交程式碼的時候,修改的原始碼是不能提上去的,要手動打包過去)
(這邊我暫時就添加了我個人覺得夠用的,只是部分沒詳細解釋,我想起來的話會更新的,如果有什麼問題可以在下面留言)