第7章 -日历组件 - calendar

沈建柏
2023-12-01

日历组件当前并没有基于element-plus封装,而是找的第三方组件库fullcalendar封装的
官方文档:https://fullcalendar.io/demos

1.首先根据需要安装包

npm install @fullcalendar/core @fullcalendar/interaction @fullcalendar/daygrid --save
--components/calendar
	--src
		--index.vue
		--types.ts
	--index.ts

src/types.ts

export interface EventItem {
  // 事件标题
  title: string,
  // 开始时间
  start: string,
  // 结束时间
  end: string,
  // 是否可拖动编辑
  editable?: boolean
}

src/index.vue

<template>
  <div id="calendar"></div>
</template>

<script lang='ts' setup>
// 在vite里面使用fullcalendar 需要引入一个包
import '@fullcalendar/core/vdom'
import { Calendar, EventClickArg, EventContentArg } from '@fullcalendar/core'
import daygridPlugin from '@fullcalendar/daygrid'
import interactionPlugin , {DateClickArg} from '@fullcalendar/interaction'
import { ref, onMounted, PropType, watch } from 'vue';
import {EventItem} from './types'

let props = defineProps({
  // 日历显示的语言
  local: {
    type: String,
    default: 'zh-cn'
  },
  // 视图模式
  initialView: {
    type: String,
    default: 'dayGridMonth'
  },
  // 按钮文字
  buttonText: {
    type: Object,
    default: () => {
      return {
        today: '今天',
        month: '月',
        week: '周',
        day: '日',
        prevYear: '上一年',
        nextYear: '下一年',
        prev: '上一月',
        next: '下一月'
      }
    }
  },
  // 头部工具栏
  headerToolbar: {
    type: Object,
    default: () => {
      return {
        start: 'title',
        center: '',
        end: 'prev today next'
      }
    }
  },
  // 底部工具栏
  footerToolbar: {
    type: Object
  },
  // 日历事件
  events: {
    type: Array as PropType<EventItem[]>,
    default: () => []
  },
  // 自定义渲染内容方法
  eventContent: {
    type: Function
  }
})

let emits = defineEmits(['date-click', 'event-click'])

// 日历对象
let calendar = ref<Calendar>()

// 生成日历的方法
let renderCalendar = () => {
  let el = document.getElementById('calendar')
  if (el) {
    // 日历的配置选项
    calendar.value = new Calendar(el, {
      // 使用到的插件
      plugins: [daygridPlugin, interactionPlugin],
      // 视图模式
      initialView: props.initialView,
      // 语言
      locale: props.local,
      // 按钮文字
      buttonText: props.buttonText,
      // 头部工具栏
      headerToolbar: props.headerToolbar, 
      // 底部工具栏
      footerToolbar: props.footerToolbar,
      // 事件源
      eventSources: [
        {
          // 生成事件
          events(e, callback) {
            if (props.events.length) callback(props.events)
            else callback([])
          }
        }
      ],
      // 点击日历的某一天
      dateClick(info: DateClickArg) {
        // console.log(info)
        emits('date-click', info)
      },
      // 点击日历上的时间
      eventClick(info: EventClickArg) {
        // console.log('eventClick', info)
        emits('event-click', info)
      },
      // 显示事件的结束时间
      displayEventEnd: true,
      // 自定义渲染内容
      eventContent: props.eventContent
    })
    calendar.value.render()
  }
}

// 监听事件源的变化
watch(() => props.events, () => {
  renderCalendar()
}, {deep: true})
onMounted(() => {
  renderCalendar()
})
</script>

<style lang='scss' scoped>
svg {
  width: 1em;
  height: 1em;
}
</style>

index.ts

import { App } from 'vue'
import calendar from './src/index.vue'

// 让这个组件可以通过use的形式使用
export default {
  install(app: App) {
    app.component('m-calendar', calendar)
  }
}

在项目中使用
views/calendar/index.vue

<template>
  <m-calendar :events="events" :eventContent="eventContent" @date-click="dateClick"></m-calendar>
</template>

<script lang='ts' setup>
import { DateClickArg } from '_@fullcalendar_interaction@5.10.1@@fullcalendar/interaction';
import { EventItem } from '../../components/calendar/src/types'
import { ref } from 'vue';
import { EventContentArg } from '@fullcalendar/core';

let events = ref<EventItem[]>([
  {
    title: '购物',
    start: '2021-11-11 10:00:00',
    end: '2021-11-11 12:00:00',
    editable: true
  },
  {
    title: '学习',
    start: '2021-11-15 08:00:00',
    end: '2021-11-15 16:00:00'
  }
])
let dateClick = (info: DateClickArg) => {
  let event = {
    start: `${info.dateStr} 12:00:00`,
    end: `${info.dateStr} 13:00:00`,
    title: '吃饭'
  }
  events.value.push(event)
  console.log(info)
}

let eventContent = (arg: EventContentArg) => {
  let el = document.createElement('div')
  let timeTextArr = arg.timeText.split(' - ')
  let start = timeTextArr[0].replace('上午', '').replace('下午', '').replace('时', '')
  let end = timeTextArr[1].replace('上午', '').replace('下午', '').replace('时', '')
  el.innerHTML = `
        <img src="src/assets/logo.png" style="width:20px;height:20px;">
         <div>开始时间: ${start}</div>
         <div>结束时间: ${end}</div>
         <div>标题: ${arg.event._def.title}</div>
        `
  return {
    domNodes: [el]
  }
}
</script>

<style lang='scss' scoped>
</style>
 类似资料: