react使用Fullcalendar 实战用法

使用步骤请参考:react使用Fullcalendar

卡片式的日历:

需求图:

卡片式的日历,其实我是推荐 antd的,我两个都写了一下都能实现。

antd 的代码:

antd的我直接用的官网示例:antd 日历示例

javascript 复制代码
import React, { useEffect, useState, useRef } from 'react';
import { Calendar, Col, Radio, Row, Select, Typography } from 'antd';
import "./index.less"
import moment from 'moment';
const ProductFullcalendar = () => {
    const [currentDate, setCurrentDate] = useState(moment()); //当前日期



    const onPanelChange = (value, mode) => {
        console.log(value.format('YYYY-MM-DD'), mode);
    };



    return (
        <div className='vv'>
            产品日历
            <Calendar
                fullscreen={false}
                onPanelChange={onPanelChange}
                dateFullCellRender={(current) => {
                    let currentDate1 = moment(current).format('YYYY-MM-DD');
                    let selectDate = currentDate.format('YYYY-MM-DD');
                    if (currentDate1 === selectDate) {
                        return <div className='dateCell selected'>
                            <div className='date_select'>{moment(current).format('DD')}</div>
                            <div className='event_select'></div>
                        </div>
                    } else {
                        return <div className='dateCell'>
                            <div className='date'>{moment(current).format('DD')}</div>

                        </div>
                    }
                }}
                onSelect={(date) => {
                    setCurrentDate(date);
                }}
            />

        </div>
    )
};
export default ProductFullcalendar;

less:

css 复制代码
.vv {
    .ant-picker-cell {
        color: rgba(0, 0, 0, 0.3);
    }

    .ant-picker-cell-in-view {
        color: rgba(0, 0, 0, 0.87);
    }

    .selected {
        background: #3D57B1;
        box-shadow: 0px 2px 6px 0px rgba(33, 77, 208, 0.36);
        border-radius: 8px;

        .date_select {
            font-family: Avenir, Avenir;
            font-weight: 500;
            font-size: 20px;
            color: #FFFFFF;
        }
        .event_select{
            width: 6px;
            height: 6px;
            background: #FFFFFF;
            border-radius: 50%;
        }
    }

    .dateCell {
        width: 48px;
        height: 55px;
        border-radius: 8px;
        margin: 0 auto;
        display: flex;
        align-items: center;
        justify-content: center;
        flex-direction: column;

        .date {
            font-family: Avenir, Avenir;
            font-weight: 500;
            font-size: 20px;
        }
        .event{
            width: 6px;
            height: 6px;
            background: red;
            border-radius: 50%;
        }
    }
}

@fullcalendar/react的代码:

它需要处理的东西很多,点击上个月的日期时,需要自己跳到上一个月。

javascript 复制代码
import React, { useEffect, useState, useRef } from 'react';
import FullCalendar from '@fullcalendar/react'
import dayGridPlugin from '@fullcalendar/daygrid'
import interactionPlugin from "@fullcalendar/interaction"
import "./index.less"
const ProductFullcalendar = () => {
    const [currentDate, setCurrentDate] = useState(); //当前日期
    // 创建一个 ref 来存储 FullCalendar 的实例  
    const calendarRef = useRef(null);
    const renderEventContent = (eventInfo) => {
        return <div className='kk'></div>
    }
    const events = [
        { title: '', start: new Date(2024, 10, 1) }
    ]
    const dayCellContent = (data) => {
        console.log(data, currentDate, "908777");
        let dayDate = data.dayNumberText.replace("日", "");
        let isToday = data.isToday;
        //是不是当月的日期
        let isOther = data.isOther;
        return <div className='dayCellContent'>
            <div className={'dayDate'}>{dayDate}</div>

        </div>
    }
    return (
        <div className='vv'>
            产品日历
            <FullCalendar
                ref={calendarRef}
                plugins={[dayGridPlugin, interactionPlugin]}
                initialView='dayGridMonth'
                events={events}
                eventContent={renderEventContent}
                dayCellClassNames={"dayCell"}
                locale='zh-cn'// 设置语言
                selectable={true}
                dateClick={(info) => {
                    document.querySelectorAll('.fc-day.selected').forEach(function (el) {
                        el.classList.remove('selected');
                    });
                    const clickedDate = info.date;
                    //console.log(calendarRef.current.getApi()?.getDate(),calendarRef,"987")
                    const currentViewDate = calendarRef?.current?.getApi()?.getDate(); // 获取当前视图的日期
                    // 判断是否为同一月份
                    if (clickedDate.getMonth() !== currentViewDate.getMonth() ||
                        clickedDate.getFullYear() !== currentViewDate.getFullYear()) {
                        // 如果不是当月日期,则切换到点击的月份
                        calendarRef?.current?.getApi()?.gotoDate(clickedDate);
                    }
                    // calendarRef?.current?.getApi()?.refetchEvents(); // 刷新事件
                    setTimeout(() => {
                        info.dayEl.classList.add('selected');
                    })
                }}
                dayHeaderClassNames={"dayHeader"}
                dayHeaderContent={(arg) => {
                    // 自定义星期内容
                    const days = ['日', '一', '二', '三', '四', '五', '六']; // 星期的中文表示
                    return days[arg.date.getDay()]; // 获取对应星期的中文名称
                }}
                dayCellContent={(data) => {
                    return dayCellContent;
                }}
            />


        </div>
    )
};
export default ProductFullcalendar;

less代码:

css 复制代码
.vv {
    --fc-border-color: none;
    --fc-highlight-color: none;
    --fc-today-bg-color: none;
    //日历总高度 包括 toolBar 和日历内容
    --fc-daygrid-height: 390px;
    // 单元格内容宽度 我自定义的
    // 单元格内容宽度 我自定义的
    --fc-daygrid-day-frame-width: 48px;
    // 单元格内容高度 我自定义的
    --fc-daygrid-day-frame-height: 55px;

    .fc-media-screen {
        height: var(--fc-daygrid-height);
    }

    .fc-header-toolbar {
        margin-bottom: 12px;
    }

    a {
        color: initial;
    }

    .fc-daygrid-day-events {
        min-height: 0 !important;
    }

    .dayCell {
        --fc-border-color: none;
        width: var(--fc-daygrid-day-frame-width);

        .fc-daygrid-day-frame {
            width: var(--fc-daygrid-day-frame-width);
            height: var(--fc-daygrid-day-frame-height);
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            flex-direction: column;
            margin: 0 auto;
        }
    }

    .fc-theme-standard th {
        border-bottom: 1px solid #F0F0F0;
    }

}

.dayHeader {
    font-weight: 400;
    font-size: 14px;
    color: rgba(0, 0, 0, 0.54) !important;
    width: var(--fc-daygrid-day-frame-width);
}

.kk {
    width: 6px;
    height: 6px;
    background: #FF7D7D;
    border-radius: 50%;
}

.fc-day-other {
    color: rgba(0, 0, 0, 0.3);
}

.fc-daygrid-day {
    color: rgba(0, 0, 0, 0.87);
}

.dayCellContent {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    line-height: 20px;

    .dayDate {
        font-family: Avenir, Avenir;
        font-weight: 800;
        font-size: 20px;
    }



    .dayEvent {
        margin-top: 2px;

        .dayEventItem {
            width: 6px;
            height: 6px;
            background: #4982F3;
            border-radius: 50%;
        }
    }

}


.selected {
    width: var(--fc-daygrid-day-frame-width);

    .fc-daygrid-day-frame {
        width: var(--fc-daygrid-day-frame-width);
        height: var(--fc-daygrid-day-frame-height);
        border-radius: 8px;
        display: flex;
        align-items: center;
        justify-content: center;
        flex-direction: column;
        margin: 0 auto;
        background: #3D57B1;
        box-shadow: 0px 2px 6px 0px rgba(33, 77, 208, 0.36);


        .fc-daygrid-day-events {
            .kk {
                width: 6px;
                height: 6px;
                background: #FFFFFF;
                border-radius: 50%;
            }
        }

        .dayCellContent {
            display: flex;
            align-items: center;
            justify-content: center;
            flex-direction: column;


            .dayDate {
                font-family: Avenir, Avenir;
                font-weight: 800;
                font-size: 20px;
                color: #FFFFFF;
            }

            .dayEvent {
                margin-top: 2px;
            }

        }
    }
}

antd官网代码:

javascript 复制代码
import { Calendar, Col, Radio, Row, Select, Typography } from 'antd';
import React from 'react';
const App = () => {
  const onPanelChange = (value, mode) => {
    console.log(value.format('YYYY-MM-DD'), mode);
  };
  return (
    <div className="site-calendar-customize-header-wrapper">
      <Calendar
        fullscreen={false}
        headerRender={({ value, type, onChange, onTypeChange }) => {
          const start = 0;
          const end = 12;
          const monthOptions = [];
          const current = value.clone();
          const localeData = value.localeData();
          const months = [];
          for (let i = 0; i < 12; i++) {
            current.month(i);
            months.push(localeData.monthsShort(current));
          }
          for (let i = start; i < end; i++) {
            monthOptions.push(
              <Select.Option key={i} value={i} className="month-item">
                {months[i]}
              </Select.Option>,
            );
          }
          const year = value.year();
          const month = value.month();
          const options = [];
          for (let i = year - 10; i < year + 10; i += 1) {
            options.push(
              <Select.Option key={i} value={i} className="year-item">
                {i}
              </Select.Option>,
            );
          }
          return (
            <div
              style={{
                padding: 8,
              }}
            >
              <Typography.Title level={4}>Custom header</Typography.Title>
              <Row gutter={8}>
                <Col>
                  <Radio.Group
                    size="small"
                    onChange={(e) => onTypeChange(e.target.value)}
                    value={type}
                  >
                    <Radio.Button value="month">Month</Radio.Button>
                    <Radio.Button value="year">Year</Radio.Button>
                  </Radio.Group>
                </Col>
                <Col>
                  <Select
                    size="small"
                    dropdownMatchSelectWidth={false}
                    className="my-year-select"
                    value={year}
                    onChange={(newYear) => {
                      const now = value.clone().year(newYear);
                      onChange(now);
                    }}
                  >
                    {options}
                  </Select>
                </Col>
                <Col>
                  <Select
                    size="small"
                    dropdownMatchSelectWidth={false}
                    value={month}
                    onChange={(newMonth) => {
                      const now = value.clone().month(newMonth);
                      onChange(now);
                    }}
                  >
                    {monthOptions}
                  </Select>
                </Col>
              </Row>
            </div>
          );
        }}
        onPanelChange={onPanelChange}
      />
    </div>
  );
};
export default App;

正常日历 antd 和 Fullcalendar 都行:

我的需求是:

我直接用的@fullcalendar/react 因为我的和它基本功能完全一致。具体怎么选看自己。

官网的demo效果:

相关推荐
Dragon Wu16 分钟前
前端框架 react 性能优化
前端·javascript·react.js·性能优化·前端框架·react
Gungnirss39 分钟前
前后端分离,后端拦截器无法获得前端请求的token
java·前端·token
五秒法则1 小时前
从搭建uni-app+vue3工程开始
前端·vue.js·uni-app
风之舞_yjf1 小时前
css基础(27)_行内、行内块元素之间的空白问题
前端·css
Kika写代码1 小时前
【基于轻量型架构的WEB开发】课程 第14章 SSM框架整合 Java EE企业级应用开发教程 Spring+SpringMVC+MyBatis
前端·架构·java-ee
WuMingf_1 小时前
CSS基础
前端·css
白水4651 小时前
基于官网的Vue-router安装(2024/11)
前端·vue.js·vue
白墨阳1 小时前
vue3:scss引用
前端·css·scss
小小优化师 anny1 小时前
纯CSS 写的一个树状触摸菜单
前端·css·css3
努力小贼2 小时前
Vue小项目(开发一个购物车)
前端·javascript·vue.js