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效果:

相关推荐
掘金者阿豪1 小时前
把业务数据变成共享仪表盘:Metabase可视化与远程访问实践
前端·后端
kyriewen1 小时前
折腾了半年 AI 编程工作流,最后发现效率瓶颈是桌上那块屏幕
前端·javascript·ai编程
蜗牛前端2 小时前
codex 全流程开发上线的高颜值礼簿小程序
前端·微信小程序
大龄秃头程序员2 小时前
我在图文流 App 里落地双层缓存、弱网降级与 OOM 治理
前端
老王以为2 小时前
React Renderer 分离的多平台架构
前端·react native·react.js
hunterandroid2 小时前
Kotlin Coroutines 与 Flow:让异步任务更清晰
前端
Bigger3 小时前
从零搭建 AI 代码审查服务:一份前端也能看懂的 Python 学习笔记
前端·ci/cd·ai编程
lichenyang4533 小时前
JSAPI、NAPI、Biz、Imp:ASCF Demo 如何真正调用系统能力和 C++ 能力
前端
lichenyang4534 小时前
IPC、JSVM、UIThread、libuv:ASCF 架构图里最容易混的几个词
前端
用户059540174464 小时前
Redis记忆存储故障恢复测试踩坑实录:手动测试让我漏掉了2个一致性Bug
前端·css