导读:本期聚焦于小伙伴创作的《React函数组件如何实现日历渲染?告别DOM操作拥抱状态驱动的方案是什么》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《React函数组件如何实现日历渲染?告别DOM操作拥抱状态驱动的方案是什么》有用,将其分享出去将是对创作者最好的鼓励。

React函数组件结合状态驱动的开发模式,可以让日历渲染逻辑更清晰,避免直接操作DOM带来的维护成本。传统的日历实现往往需要手动创建、修改DOM节点,而状态驱动方案只需要更新对应的状态,React会自动完成视图的更新。

React函数组件如何实现日历渲染?告别DOM操作拥抱状态驱动的方案是什么

核心实现思路

日历渲染的核心是先计算出当前月份需要展示的所有日期,再通过状态管理这些日期的展示逻辑。主要包含三个部分:状态定义、日期计算、视图渲染。

1. 状态定义

首先需要定义控制日历的核心状态,包括当前选中的年份、月份,以及需要展示的日期列表。

import { useState, useEffect } from 'react';

const Calendar = () => {
  // 当前选中的年份
  const [currentYear, setCurrentYear] = useState(new Date().getFullYear());
  // 当前选中的月份,0代表1月,11代表12月
  const [currentMonth, setCurrentMonth] = useState(new Date().getMonth());
  // 当前月份需要展示的日期数组
  const [dateList, setDateList] = useState([]);
  // 当前选中的日期
  const [selectedDate, setSelectedDate] = useState(null);

  return (
    <div className="calendar-container">
      {/* 后续渲染内容 */}
    </div>
  );
};

export default Calendar;

2. 日期计算逻辑

需要根据当前选中的年份和月份,计算出该月的第一天是周几,以及该月的总天数,同时补充上个月末尾和下个月开头的日期,保证日历完整显示6行。

// 计算指定年月的天数
const getMonthDays = (year, month) => {
  return new Date(year, month + 1, 0).getDate();
};

// 计算指定年月第一天是周几,0代表周日,6代表周六
const getFirstDayOfWeek = (year, month) => {
  return new Date(year, month, 1).getDay();
};

// 生成日期列表的方法
const generateDateList = () => {
  const monthDays = getMonthDays(currentYear, currentMonth);
  const firstDay = getFirstDayOfWeek(currentYear, currentMonth);
  const list = [];

  // 补充上个月的末尾日期
  const prevMonthDays = getMonthDays(currentYear, currentMonth - 1);
  for (let i = firstDay - 1; i >= 0; i--) {
    list.push({
      date: prevMonthDays - i,
      isCurrentMonth: false,
      fullDate: `${currentYear}-${currentMonth === 0 ? currentYear - 1 : currentYear}-${currentMonth === 0 ? 12 : currentMonth}`
    });
  }

  // 补充当前月的日期
  for (let i = 1; i <= monthDays; i++) {
    list.push({
      date: i,
      isCurrentMonth: true,
      fullDate: `${currentYear}-${currentMonth + 1}-${i}`
    });
  }

  // 补充下个月的开头日期,保证总长度为42(6行*7列)
  const remainCount = 42 - list.length;
  for (let i = 1; i <= remainCount; i++) {
    list.push({
      date: i,
      isCurrentMonth: false,
      fullDate: `${currentYear}-${currentMonth === 11 ? currentYear + 1 : currentYear}-${currentMonth === 11 ? 1 : currentMonth + 2}`
    });
  }

  setDateList(list);
};

// 年份或月份变化时重新生成日期列表
useEffect(() => {
  generateDateList();
}, [currentYear, currentMonth]);

3. 视图渲染与交互

基于生成的日期列表渲染日历视图,同时实现月份切换、日期选中、高亮今天等交互功能,所有操作都通过修改状态实现,不需要操作DOM。

// 星期标题
const weekTitles = ['日', '一', '二', '三', '四', '五', '六'];

// 切换到上一个月
const goToPrevMonth = () => {
  if (currentMonth === 0) {
    setCurrentYear(currentYear - 1);
    setCurrentMonth(11);
  } else {
    setCurrentMonth(currentMonth - 1);
  }
};

// 切换到下一个月
const goToNextMonth = () => {
  if (currentMonth === 11) {
    setCurrentYear(currentYear + 1);
    setCurrentMonth(0);
  } else {
    setCurrentMonth(currentMonth + 1);
  }
};

// 选中日期
const handleDateClick = (item) => {
  setSelectedDate(item.fullDate);
};

// 判断是否是今天
const isToday = (item) => {
  const today = new Date();
  const todayStr = `${today.getFullYear()}-${today.getMonth() + 1}-${today.getDate()}`;
  return item.fullDate === todayStr;
};

return (
  <div className="calendar-container">
    {/* 头部控制栏 */}
    <div className="calendar-header">
      <button onClick={goToPrevMonth}>上个月</button>
      <span className="current-month">{currentYear}年{currentMonth + 1}月</span>
      <button onClick={goToNextMonth}>下个月</button>
    </div>
    {/* 星期标题行 */}
    <div className="week-row">
      {weekTitles.map((title, index) => (
        <div key={index} className="week-item">{title}</div>
      ))}
    </div>
    {/* 日期网格 */}
    <div className="date-grid">
      {dateList.map((item, index) => (
        <div
          key={index}
          className={`date-item ${item.isCurrentMonth ? '' : 'other-month'} ${isToday(item) ? 'today' : ''} ${selectedDate === item.fullDate ? 'selected' : ''}`}
          onClick={() => handleDateClick(item)}
        >
          {item.date}
        </div>
      ))}
    </div>
  </div>
);

样式补充说明

可以通过CSS为日历添加基础样式,这里提供简单的样式参考,不需要操作DOM,只需要定义类名即可。

.calendar-container {
  width: 400px;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  padding: 16px;
}

.calendar-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
}

.current-month {
  font-size: 18px;
  font-weight: bold;
}

.week-row {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  text-align: center;
  margin-bottom: 8px;
}

.week-item {
  padding: 8px 0;
  font-weight: bold;
}

.date-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
}

.date-item {
  padding: 12px 0;
  text-align: center;
  cursor: pointer;
  border-radius: 4px;
}

.date-item:hover {
  background-color: #f5f5f5;
}

.other-month {
  color: #ccc;
}

.today {
  background-color: #e6f7ff;
  color: #1890ff;
}

.selected {
  background-color: #1890ff;
  color: #fff;
}

方案优势

  • 不需要手动操作DOM节点,所有视图更新由React自动完成,减少出错概率
  • 状态逻辑和视图逻辑分离,代码可读性和可维护性更高
  • 扩展功能更方便,比如添加节假日标记、日程展示等功能,只需要新增对应的状态和渲染逻辑即可
  • 符合React的函数式编程思想,充分利用hooks的能力管理组件状态

这种状态驱动的日历实现方案,完全避免了原生DOM操作的繁琐,是React函数组件开发日历功能的推荐方式。开发者可以根据实际需求扩展更多功能,比如日期范围选择、农历显示等,核心思路都是基于状态管理实现视图更新。

React函数组件日历渲染状态驱动修改时间:2026-07-19 04:51:34

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。