当前位置:首页 > React

react实现携程日历

2026-01-26 11:10:58React

实现携程日历的React组件

创建一个类似携程的日历组件需要处理日期选择、区间高亮、禁用日期等逻辑。以下是关键实现步骤:

日期选择与区间高亮

使用date-fns库处理日期操作,实现开始/结束日期选择和区间高亮效果:

import { format, addDays, isBefore, isAfter, isSameDay } from 'date-fns';

function DateRangePicker({ startDate, endDate, onDateSelect }) {
  const handleDateClick = (date) => {
    if (!startDate || (startDate && endDate)) {
      onDateSelect({ startDate: date, endDate: null });
    } else if (isBefore(date, startDate)) {
      onDateSelect({ startDate: date, endDate: startDate });
    } else {
      onDateSelect({ startDate, endDate: date });
    }
  };

  const renderDays = () => {
    const days = [];
    const currentDate = new Date();

    for (let i = 0; i < 42; i++) { // 6周
      const date = addDays(currentDate, i);
      const isSelected = 
        (startDate && isSameDay(date, startDate)) || 
        (endDate && isSameDay(date, endDate));
      const isInRange = 
        startDate && endDate && 
        isAfter(date, startDate) && 
        isBefore(date, endDate);

      days.push(
        <div 
          key={date}
          className={`day ${isSelected ? 'selected' : ''} ${isInRange ? 'in-range' : ''}`}
          onClick={() => handleDateClick(date)}
        >
          {format(date, 'd')}
        </div>
      );
    }

    return days;
  };

  return <div className="date-range-picker">{renderDays()}</div>;
}

禁用日期处理

添加禁用日期逻辑,比如限制可选日期范围或排除特定日期:

const isDateDisabled = (date) => {
  const today = new Date();
  const maxSelectableDate = addDays(today, 180); // 限制半年内
  return isBefore(date, today) || isAfter(date, maxSelectableDate);
};

// 在renderDays中修改
const disabled = isDateDisabled(date);
<div 
  className={`day ${disabled ? 'disabled' : ''}`}
  onClick={!disabled ? () => handleDateClick(date) : undefined}
>
  {format(date, 'd')}
</div>

月份切换与布局

实现月份导航和符合携程视觉风格的布局:

function Calendar() {
  const [currentMonth, setCurrentMonth] = useState(new Date());

  const prevMonth = () => setCurrentMonth(subMonths(currentMonth, 1));
  const nextMonth = () => setCurrentMonth(addMonths(currentMonth, 1));

  return (
    <div className="ctrip-calendar">
      <div className="header">
        <button onClick={prevMonth}>&lt;</button>
        <h3>{format(currentMonth, 'yyyy年MM月')}</h3>
        <button onClick={nextMonth}>&gt;</button>
      </div>
      <div className="weekdays">
        {['日', '一', '二', '三', '四', '五', '六'].map(day => (
          <div key={day}>{day}</div>
        ))}
      </div>
      <DateRangePicker 
        startDate={startDate} 
        endDate={endDate} 
        onDateSelect={setDates}
      />
    </div>
  );
}

样式设计

添加CSS实现携程风格的视觉效果:

.ctrip-calendar {
  width: 350px;
  border: 1px solid #eee;
  border-radius: 8px;
  padding: 10px;
}

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

.weekdays {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  text-align: center;
  color: #666;
}

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

.day {
  padding: 8px;
  text-align: center;
  cursor: pointer;
  border-radius: 4px;
}

.day.selected {
  background-color: #008489;
  color: white;
}

.day.in-range {
  background-color: #e6f7ff;
}

.day.disabled {
  color: #ccc;
  cursor: not-allowed;
}

完整组件集成

将所有功能集成到完整组件中:

react实现携程日历

import React, { useState } from 'react';
import { 
  format, addDays, subMonths, addMonths, 
  isBefore, isAfter, isSameDay 
} from 'date-fns';

export default function CtripCalendar() {
  const [currentMonth, setCurrentMonth] = useState(new Date());
  const [selectedDates, setSelectedDates] = useState({
    startDate: null,
    endDate: null
  });

  return (
    <div className="ctrip-calendar-container">
      <Calendar 
        currentMonth={currentMonth}
        onMonthChange={setCurrentMonth}
        selectedDates={selectedDates}
        onDateSelect={setSelectedDates}
      />
    </div>
  );
}

优化与扩展

  1. 添加动画过渡效果提升用户体验
  2. 实现多个月份并排显示
  3. 集成价格日历功能(显示每日价格)
  4. 添加节假日特殊标记
  5. 实现移动端触摸滑动切换月份

以上实现提供了携程日历的核心功能,可根据实际需求调整样式和交互细节。使用date-fns处理日期操作比原生Date API更可靠,组件设计遵循了React的最佳实践。

标签: 携程日历
分享给朋友:

相关文章

vue实现日历

vue实现日历

Vue 实现日历的基本方法 使用 Vue 实现日历可以通过自定义组件或借助第三方库完成。以下是两种常见实现方式: 自定义日历组件 创建基于 Vue 的日历组件需要处理日期计算和渲染逻辑。核心是生成当…

vue实现日历插件

vue实现日历插件

Vue 日历插件实现方案 使用现成组件库 推荐直接使用成熟的 Vue 日历组件,如: V-Calendar:专为 Vue 设计的轻量级日历组件 FullCalendar:功能强大的日历库,有 Vue…

vue表格实现日历

vue表格实现日历

Vue 表格实现日历的方法 基础表格结构 使用 el-table 或原生 HTML 表格,通过 v-for 循环生成日历格子。月份天数通过 new Date() 计算,动态渲染表格内容。 &…

用vue实现日历

用vue实现日历

实现基础日历结构 使用Vue构建日历需要先设计基础数据结构。通常需要维护当前年份、月份以及日期数组。可以通过Date对象获取当前月份的天数和起始星期。 data() { return {…

vue实现iview日历显示

vue实现iview日历显示

实现步骤 安装必要的依赖库iview和vue。通过npm或yarn进行安装: npm install iview vue 在main.js中引入iview并注册组件: import Vue fro…