Vue日历,FullCalendar 使用及兼容IE10+

2020-08-12  本文已影响0人  ErHu丶

FullCalendar v4.1.0版本

效果图(月)
效果图(周)

以下是部分代码,看懂逻辑即可:

// package.json 引入
"dependencies": {
    "@fullcalendar/core": "^4.1.0",
    "@fullcalendar/daygrid": "^4.1.0",
    "@fullcalendar/interaction": "^4.1.0",
    "@fullcalendar/timegrid": "^4.1.0",
    "@fullcalendar/vue": "^4.1.0"
}

IE10需要单独引入此方法:
Intl.complete.js 来源: https://github.com/andyearnshaw/Intl.js/blob/master/dist/Intl.complete.js

  <!-- 日历组件支持IE10 -->
  <script type="text/javascript" src="./vendor/Intl.complete.js"></script>
  <script>window.Intl = window.IntlPolyfill</script>
  <!-- popper 弹窗库 -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/jquery.webui-popover/1.2.18/jquery.webui-popover.min.css">
  <script src="//cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js"></script>
  <script src="https://cdn.jsdelivr.net/jquery.webui-popover/1.2.18/jquery.webui-popover.min.js"></script>

对应页面的初始化代码。

<template>
  <div class="calendar-container">
    <FullCalendar
      ref="calendar"
      v-loading="loading"
      class="calendar"
      :style="{ width: calendarOptions.width + 'px' }"
      :locale="calendarOptions.locale"
      :default-view="calendarOptions.initialView"
      :buttonText="calendarOptions.buttonText"
      :header="calendarOptions.headerToolbar"
      :plugins="calendarOptions.plugins"
      :all-day-slot="calendarOptions.allDaySlot"
      :height="calendarOptions.height"
      :custom-buttons="calendarOptions.customButtons"
      :slot-duration="calendarOptions.slotDuration"
      :slot-label-interval="calendarOptions.slotLabelInterval"
      :slot-min-time="calendarOptions.slotMinTime"
      :slot-max-time="calendarOptions.slotMaxTime"
      :scroll-time="calendarOptions.scrollTime"
      :slot-label-format="calendarOptions.slotLabelFormat"
      :event-time-format="calendarOptions.eventTimeFormat"
      :events="getCalendarEvents"
      @datesRender="datesRender"
      @eventMouseEnter="eventMouseEnter"
    />
    <popper v-show="false" :data-item="popperData"></popper>
  </div>
</template>

<script>
// See https://fullcalendar.io/docs#toc version: v4!
import FullCalendar from '@fullcalendar/vue'
import dayGridPlugin from '@fullcalendar/daygrid'
import timeGridPlugin from '@fullcalendar/timegrid'
import interactionPlugin from '@fullcalendar/interaction'
import cnLocale from '@fullcalendar/core/locales/zh-cn'
import Popper from './Popper.vue'
import { mapGetters } from 'vuex'
import defaultSettings from '@/settings.js'

export default {
  name: 'Calendar',
  components: {
    FullCalendar,
    Popper
  },
  props: {
    loading: {
      type: Boolean,
      required: true,
      default: () => false
    }
  },
  computed: {
    ...mapGetters({
      calendarData: 'teacher/calendarData',
    })
  },
  watch: {
    calendarData: {
      immediate: true,
      handler(newVal) {
        this.configCalendarData(newVal)
      }
    }
  },
  data() {
    const _this = this
    return {
      calendarOptions: {
        locale: cnLocale,
        plugins: [dayGridPlugin, timeGridPlugin, interactionPlugin],
        headerToolbar: { // 配置Header的操作按钮和位置
          left: 'timeGridWeek,dayGridMonth',
          center: 'prev title next today',
          right: 'allCourseButton'
        },
        buttonText: {
          today: '本周'
        },
        customButtons: {
          allCourseButton: {
            text: '查看所有课程',
            click: function() {
              _this.$router.push('/teacher/list')
            }
          }
        },
        height: 795, // 日历高度
        slotLabelInterval: '00:15', // 时间间隔
        slotDuration: '00:15:00', // 时间间隔
        slotMinTime: '00:00',
        slotMaxTime: '24:00',
        scrollTime: '08:00', // 默认展示的时间
        slotLabelFormat: { // 周时间的左侧时间轴配置
          hour12: false,
          hour: '2-digit',
          minute: '2-digit'
        },
        eventTimeFormat: {
          hour12: false,
          hour: '2-digit',
          minute: '2-digit'
        },
        allDaySlot: false,
        events: this.getCalendarEvents,
        eventMouseEnter: this.eventMouseEnter,
        initialView: 'timeGridWeek' // 初始化时展示的类型
      },
      calendarEvents: [],
      calendarApi: '', // 日历实例
      popperData: {}, // 当前弹窗的数据
      currentPopper: false, // 当前弹窗的实例
      eventControl: false, // 用于事件节流
      containerWidth: 800 // 用于判断弹出窗口朝左还是朝右
    }
  },
  mounted() {
    // 日历的实例
    this.calendarApi = this.$refs.calendar.getApi()
    // 获取页面宽度高度, 需要用到
    const container = document.querySelector('.teacher-schedule-container')
    this.calendarOptions.height = container.clientHeight
    this.containerWidth = container.clientWidth
  },
  methods: {
    datesRender(info) {
      // 日历类型改变回调
      if (info.view.type === 'dayGridMonth') {
        $('.fc-today-button').text('本月')
      } else if (info.view.type === 'timeGridWeek') {
        $('.fc-today-button').text('本周')
      }
    },
    eventMouseEnter(event) {
      // 设置弹窗数据
      this.$set(this, 'popperData', event.event.extendedProps)
      const el = $(event.el)
      const offset = event.el.getBoundingClientRect()
      const position = offset.right
      this.$nextTick(() => {
        // 根据位置弹出汽泡
        // See: https://github.com/sandywalker/webui-popover
        el.webuiPopover({
          // 如果位置太靠右就在左侧显示
          placement: position + 300 > this.containerWidth ? 'left' : 'right',
          container: document.body,
          trigger: 'hover',
          url: '#popper',
          padding: false,
          animation: 'pop',
          cache: false,
          onShow: () => {
            // 隐藏原有Dom上的元素
            $('.calendar-container .popper-container').hide()
            try {
              // 添加点击事件, 原Dom上的加不了, 只能这样加
              $('body .popper-container .live-button').last().click(() => {
                // 弹窗上的按钮点击了
              })
            } catch (e) {
              // eslint-disable-next-line
            }
          },
          onHide: () => {
            el.webuiPopover('destroy')
          }
        })
        el.webuiPopover('show')
      })
    },
    getCalendarEvents(info, cbk) {
      // 返回日历的事件集合
      cbk(this.calendarEvents)
    },
    configCalendarData(datas) {
      // 配置日历数据源
      let events = []
      for (let i = 0; i < datas.length; i++) {
        const item = datas[i]
        const color = item.Status === '已结束' ? '#adadad' : '#ff9c5a'
        events.push({
          id: item.HourGuid,
          backgroundColor: color,
          borderColor: color,
          title: item.HourName,
          extendedProps: item,
          start: new Date(item.HourStart.replace(/-/g, '/')), // IE不支持 2019-01-01, 支持2019/01/01
          end: new Date(item.HourEnd.replace(/-/g, '/'))
        })
      }
      this.calendarEvents = events
      this.calendarApi.refetchEvents()
    }
  }
}
</script>

<style type="text/css">
/* 气泡弹窗UI */
  .webui-popover {
    border: 0 !important;
    box-shadow: 0 1px 10px rgba(0,0,0,.2) !important;
  }

  .webui-popover .webui-arrow {
    border-right-color: #f0f0f0 !important;
    border-left-color: #f0f0f0 !important;
  }

</style>

<style lang="scss" scoped>

@import '~@fullcalendar/core/main.css';
@import '~@fullcalendar/daygrid/main.css';
@import '~@fullcalendar/timegrid/main.css';

  .calendar-container {
    width: calc(100vw - 80px);
    min-width: 1120px;

    // 头部操作按钮相关CSS
    ::v-deep .fc-header-toolbar {
      display: flex;

      .fc-button {
        background-color: #fff;
        border: 1px solid #dcdfe6;
        color: #418aec;
        font-size: 14px;
      }

      .fc-center {
        display: flex;
      }

      .fc-button-active {
        background-color: #418aec;
        border: 1px solid #418aec;
        color: #fff;
      }

      .fc-button:focus {
        box-shadow: none;
      }

      .fc-timeGridWeek-button, .fc-dayGridMonth-button {
        padding: 8px 30px;
      }

      .fc-allCourseButton-button {
        border: 0;
        background-color: #418aec;
        color: #fff;
        // font-size: 13px;
        padding: 8px 18px;
      }

      .fc-today-button {
        font-weight: bold;
        border: 0;
        padding-left: 20px;
      }
    }

    // 周日历事件相关CSS
    ::v-deep .fc-time-grid {
      .fc-title {
        text-overflow: ellipsis;
        white-space: nowrap;
        overflow: hidden;
      }

      .fc-time-grid-event {
        padding: 5px;
        font-weight: bold;
      }

    }

    ::v-deep .fc-day-grid-container .fc-title {
      position: absolute;
      left: 45px;
      right: 0;
      text-overflow: ellipsis;
      overflow: hidden;
    }

    // 修改非当月日期背景色为灰色
    ::v-deep .fc-other-month {
      background-color: #f0f0f0;
    }

    // 修改当天在日历中的背景颜色
    ::v-deep .fc-today {
      background-color: #fff;
    }
  }
</style>

Popper 组件内容:

<template>
  <div id="popper" ref="popper" class="popper-container">
    <div class="content">名称: {{ dataItem.Name }}</div>
    <!-- 省略其他字段 -->
    <el-button round class="live-button">可点击按钮</el-button>
  </div>
</template>

<script>
export default {
  name: 'Popper',
  props: {
    dataItem: {
      type: Object,
      required: false,
      default: () => {}
    }
  }
}
</script>

<style lang="scss" scoped>

  .popper-container {
    background: #fff;
    padding: 15px 20px;
    font-size: 15px;
    border-radius: 4px;
    z-index: -1;
    width: 200px !important;
    text-align: center;
    max-height: 300px !important;
    overflow-y: auto;
    display: none;

    .content {
      font-size: 14px;
      line-height: 20px;
      padding-bottom: 10px;
      text-align: left;
    }

    .live-button {
      border-color: #418aec;
      background-color: #418aec;
      margin-top: 10px;
      margin-bottom: 5px;
      width: 160px;
    }
  }
</style>
上一篇下一篇

猜你喜欢

热点阅读