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
相关产品推荐
相关产品推荐

