Skip to content

日历组件

注意

  1. 日历组件我在这里用的就是Fullcalendar

  2. 个人觉得他是前端最强的日历组件,没有之一

基本使用

官方文档

安装

  • Vue2
js
npm install --save @fullcalendar/vue
//下面包是日历的周视图、日视图等插件包:
npm install --save @fullcalendar/core @fullcalendar/daygrid @fullcalendar/interaction @fullcalendar/list @fullcalendar/timegrid
//安装后的fullcalendar源码和其它插件都会在@fullcalendar
npm install --save dayjs 
//安装dayjs用于格式化时间格式
  • Vue3
bash

npm install --save @fullcalendar/vue3
//下面包是日历的周视图、日视图等插件包:
npm install --save @fullcalendar/core @fullcalendar/daygrid @fullcalendar/interaction @fullcalendar/list @fullcalendar/timegrid
//安装后的fullcalendar源码和其它插件都会在@fullcalendar
npm install --save dayjs 
//安装dayjs用于格式化时间格式

架构

bash
├── src
   ├── components
   ├── chooseCalendar
      ├── lib (引入的第三方库)
    └── xxx.json
      ├── src (源码)
   ├── index.vue
      ├── index.ts

index.ts

ts
import { type App } from 'vue'
import chooseCalendar from './src/index.vue'

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

interface/chooseCalendar/type.ts

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

components/chooseCalendar/src/index.vue

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

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

    let props = defineProps({
        // 日历显示的语言
        local: {
            type: String,
            default: 'zh-cn'
        },
        // 视图模式
        initialView: {
            type: String,
            default: 'dayGridMonth'
        },
        // 按钮文字
        buttonText: {
            type: Object,
            default: () => {
                return {
                    today: '今天',
                    month: '月',
                    week: '周',
                    day: '日'
                }
            }
        },
        // 头部工具栏
        headerToolbar: {
            type: Object,
            default: () => {
                return {
                    left: 'prev,next, today',
                    center: 'title',
                    right: 'dayGridMonth,timeGridWeek,timeGridDay'
                }
            }
        },
        // 底部工具栏
        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, timeGridPlugin],
                // 视图模式
                initialView: props.initialView,
                // 语言
                locale: props.local,
                // 按钮文字
                buttonText: props.buttonText,
                // 头部工具栏
                headerToolbar: props.headerToolbar,
                // 底部工具栏
                footerToolbar: props.footerToolbar,
                // 显示周末
                weekends: true,
                // 事件源
                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,
                // 拖拽合集开始
                editable: true, // 启用事件拖拽和调整大小
                droppable: true, // 启用外部元素拖拽到日历
                eventDrop: function (info) {
                    console.log('Event dropped: ' + info.event.title)
                    console.log(info)
                    console.log('开始时间:' + info.event.startStr)
                    console.log('结束时间:' + info.event.endStr)
                    console.log('结束时间:' + info.event.title)
                },
                eventResize: function (info) {
                    console.log('Event resized: ' + info.event.title)
                    console.log(info)
                },
                drop: function (info) {
                    console.log('Dropped')
                    console.log(info)
                    console.log(info.view.calendar)
                }
                // 拖拽合集结束
            })
            calendar.value.render()
        }
    }

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

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

父元素调用

vue

<template>
    <div>
        <YJ-choose-calendar :events="events" :eventContent="eventContent" @date-click="dateClick"></YJ-choose-calendar>
    </div>
</template>

<script setup lang="ts">
    import { type DateClickArg } from '@fullcalendar/interaction'
    import { type EventItem } from '@/interfaces/chooseCalendar/type'
    import { ref } from 'vue'
    import { type EventContentArg } from '@fullcalendar/core'
    import dayjs from 'dayjs'
    let events = ref<EventItem[]>([
        {
            title: '购物',
            start: '2025-02-04 10:00:00',
            end: '2025-02-06 12:00:00',
            editable: true
        },
        {
            title: '学习',
            start: '2025-02-05 08:00:00',
            end: '2025-02-05 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 start = `${dayjs(arg.event.start).format('YYYY-MM-DD HH:mm:ss')}时开始`
        let end = `${dayjs(arg.event.end).format('YYYY-MM-DD HH:mm:ss')}时结束`
        el.innerHTML = `
        <img src="https://file.jsopy.com/IMAGES/avatar.jpg" style="width:20px;height:20px;">
         <div>开始时间: ${start}</div>
         <div>结束时间: ${end}</div>
         <div>标题: ${arg.event.title}</div>
        `
        return {
            domNodes: [el]
        }
    }
</script>

<style scoped></style>