You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React项目:渲染选中日期时段下拉框及相关功能实现

解决方案:React日期时段选择组件优化

嘿,针对你提出的三个需求,我整理了一套可行的实现方案,咱们一步步来搞定:

1. 核心状态规划

首先得明确组件需要管理的状态,咱们用useState来定义:

const [dates, setDates] = useState([]); // 后端返回的完整日期数组
const [visibleDates, setVisibleDates] = useState([]); // 当前显示的日期(默认前5个)
const [selectedDate, setSelectedDate] = useState(null); // 选中的日期
const [selectedTimeSlot, setSelectedTimeSlot] = useState(''); // 选中的时段

2. 渲染选中日期的时段到<select>

当用户选中某个日期后,咱们从dates数组里找到对应日期的时段列表,然后映射成<option>选项:

// 渲染时段选择框
const renderTimeSlots = () => {
  if (!selectedDate) return <select disabled><option>请先选择日期</option></select>;
  
  const timeSlots = dates.find(date => date.id === selectedDate.id)?.slots || [];
  return (
    <select 
      value={selectedTimeSlot}
      onChange={(e) => setSelectedTimeSlot(e.target.value)}
    >
      <option value="">请选择时段</option>
      {timeSlots.map(slot => (
        <option key={slot.id} value={slot.value}>
          {slot.label}
        </option>
      ))}
    </select>
  );
};

3. 实现“加载更多”日期功能

默认只显示前5个日期,点击“加载更多”按钮后,每次追加5个(直到显示全部):

// 初始化加载前5个日期(可以在获取后端数据后调用)
useEffect(() => {
  // 假设这里是从后端获取dates的逻辑,比如axios.get(...).then(res => setDates(res.data))
  // 初始化显示前5个
  if (dates.length > 0) {
    setVisibleDates(dates.slice(0, 5));
  }
}, [dates]);

// 加载更多日期的函数
const handleLoadMore = () => {
  const nextCount = visibleDates.length + 5;
  setVisibleDates(dates.slice(0, nextCount));
};

// 渲染日期列表+加载更多按钮
const renderDateList = () => {
  return (
    <div className="date-list">
      {visibleDates.map(date => (
        <div 
          key={date.id}
          className={`date-item ${selectedDate?.id === date.id ? 'active' : ''}`}
          onClick={() => {
            setSelectedDate(date);
            // 切换日期时重置选中的时段
            setSelectedTimeSlot('');
          }}
        >
          {date.label}
        </div>
      ))}
      {visibleDates.length < dates.length && (
        <button onClick={handleLoadMore} className="load-more-btn">
          加载更多
        </button>
      )}
    </div>
  );
};

4. 整合完整组件示例

把上面的逻辑整合到一个完整的函数组件里:

import { useState, useEffect } from 'react';

const DateTimeSelector = () => {
  const [dates, setDates] = useState([]);
  const [visibleDates, setVisibleDates] = useState([]);
  const [selectedDate, setSelectedDate] = useState(null);
  const [selectedTimeSlot, setSelectedTimeSlot] = useState('');

  // 模拟后端数据请求
  useEffect(() => {
    const mockDates = [
      { id: 1, label: '2024-05-20', slots: [{ id: '1-1', value: '09:00-10:00', label: '09:00-10:00' }, { id: '1-2', value: '10:00-11:00', label: '10:00-11:00' }] },
      { id: 2, label: '2024-05-21', slots: [{ id: '2-1', value: '14:00-15:00', label: '14:00-15:00' }, { id: '2-2', value: '15:00-16:00', label: '15:00-16:00' }] },
      { id: 3, label: '2024-05-22', slots: [{ id: '3-1', value: '09:00-10:00', label: '09:00-10:00' }] },
      { id: 4, label: '2024-05-23', slots: [{ id: '4-1', value: '16:00-17:00', label: '16:00-17:00' }] },
      { id: 5, label: '2024-05-24', slots: [{ id: '5-1', value: '10:00-11:00', label: '10:00-11:00' }] },
      { id: 6, label: '2024-05-25', slots: [{ id: '6-1', value: '14:00-15:00', label: '14:00-15:00' }] },
      { id: 7, label: '2024-05-26', slots: [{ id: '7-1', value: '09:00-10:00', label: '09:00-10:00' }] },
    ];
    setDates(mockDates);
  }, []);

  useEffect(() => {
    if (dates.length > 0) {
      setVisibleDates(dates.slice(0, 5));
    }
  }, [dates]);

  const handleLoadMore = () => {
    const nextCount = visibleDates.length + 5;
    setVisibleDates(dates.slice(0, nextCount));
  };

  const renderTimeSlots = () => {
    if (!selectedDate) return <select disabled><option>请先选择日期</option></select>;
    
    const timeSlots = dates.find(date => date.id === selectedDate.id)?.slots || [];
    return (
      <select 
        value={selectedTimeSlot}
        onChange={(e) => setSelectedTimeSlot(e.target.value)}
      >
        <option value="">请选择时段</option>
        {timeSlots.map(slot => (
          <option key={slot.id} value={slot.value}>
            {slot.label}
          </option>
        ))}
      </select>
    );
  };

  const renderDateList = () => {
    return (
      <div className="date-list">
        {visibleDates.map(date => (
          <div 
            key={date.id}
            className={`date-item ${selectedDate?.id === date.id ? 'active' : ''}`}
            onClick={() => {
              setSelectedDate(date);
              setSelectedTimeSlot('');
            }}
          >
            {date.label}
          </div>
        ))}
        {visibleDates.length < dates.length && (
          <button onClick={handleLoadMore} className="load-more-btn">
            加载更多
          </button>
        )}
      </div>
    );
  };

  return (
    <div className="date-time-selector">
      {renderDateList()}
      <div className="time-slot-container">
        {renderTimeSlots()}
      </div>
      {/* 可以在这里显示选中的结果,用于调试或展示给用户 */}
      {selectedDate && selectedTimeSlot && (
        <p className="selected-info">
          已选中:{selectedDate.label} {selectedTimeSlot}
        </p>
      )}
    </div>
  );
};

export default DateTimeSelector;

关键注意点

  • 切换日期时记得重置时段选中状态,避免出现日期和时段不匹配的情况;
  • 加载更多时要判断是否已经显示全部日期,避免按钮重复显示;
  • 如果后端数据量很大,可以考虑做虚拟滚动优化,但默认的slice方式已经能满足大部分场景;
  • 给<select>添加disabled属性,在未选择日期时禁止操作,能提升用户体验。

内容的提问来源于stack exchange,提问作者ST80

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:09:05