【山竹记账前端-react】18.自制日期选择器(下)
大纲链接 §
[toc]
1. 一列变三列 ⇧
提取单个日期栏组件到
DateTimeColumn.tsx
|
|
@/components/form/DatePickerPopup.tsx
|
|
2. useRef 配合 forceUpdate ⇧
添加月日列重,构组件 ⇧
重构
@/components/form/DateTimeColumn.tsx解耦年份数据,只需要dateTimeValue和dateTimeList
|
|
- 容器总高度需要写死
h-[var(--popup-height)]
重构
@/components/form/DatePickerPopup.tsx添加月份、日列表数据
|
|
日期栏联动,onChange 触发日期栏切换 ⇧
@/components/form/DateTimeColumn.tsx
|
|
- 组件接受父组件传参方法
onChange - 在
onTouchEnd时触发onChange onChange时将当前时间选项值,通过计算dateTimeList的索引,传递给父组件dateTimeList[Math.abs(resultY / dateItemHeight)]
使用
useRef + forceUpdate改造@/components/form/DatePickerPopup.tsx
|
|
- 需要强行设置一个空对象的状态
const [_, forceUpdate] = useState({}) - 每次更新组件只声明一次变量使用
useRefconst valueTime = useRef(value ? createDateTime(value) : createDateTime())
- 当切换日期栏,每次都需要重新计算
dayList - 使用
useRef + forceUpdate- 值放到一个固定的对象上
const valueTime = useRef(value ? createDateTime(value) : createDateTime()) - 声明强行更行更新方法
const [_, forceUpdate] = useState({}) - 状态变更时添加
forceUpdate({}) const onChangeYear = (value) => {valueTime.current.year = ...; forceUpdate({})}
- 值放到一个固定的对象上
父组件
@/modules/items/input/DateInput.tsx通过onChange拿到新的日期值,再设置到日期对象中valueTime
|
|
目前还有 bug
- 从闰年的
02-29切换到平年时,实际日期到了03-01 dateTimeValue变化时,没有去更新UI
3. value变化时更新偏移量y ⇧
Debug 调试精髓
@/components/form/DateTimeColumn.tsx
未更新
UI中的currentDateIndex1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64import { animated, useSpring } from '@react-spring/web' import { cn } from 'cn' import { TouchEventHandler, useEffect, useState } from 'react' interface ColumnProps { className?: string dateItemHeight?: number dateTimeValue: string dateTimeList: string[] onChange: (value: string) => void } export const DateTimeColumn: React.FC<ColumnProps> = ({ className, dateItemHeight = 36, dateTimeValue, dateTimeList, onChange, }) => { useEffect(() => { console.log('DateTimeColumn_______________________') console.log('%c⧭', 'color: #00ff88', dateTimeValue) console.log('_______________________DateTimeColumn') }, [dateTimeValue]) const halfDateItemHeight = dateItemHeight / 2 const itemHeightVarStyle = {/* ... */} const currentDateIndex = dateTimeList.indexOf(dateTimeValue) if (currentDateIndex === -1) {/* ... */} const [isTouching, setIsTouching] = useState(false) const [lastY, setLastY] = useState(-1) const [translateY, setTranslateYState] = useState(currentDateIndex * -dateItemHeight) const springStyle = useSpring({/* ... */}) const setTranslateY = (y: number) => {/* ... */} const onTouchStart: TouchEventHandler<HTMLDivElement> = (e) => {/* ... */} const onTouchMove: TouchEventHandler<HTMLDivElement> = (e) => {/* ... */} const onTouchEnd: TouchEventHandler<HTMLDivElement> = (/* e */) => {/* ... */} return ( <div onTouchStart={onTouchStart} onTouchMove={onTouchMove} onTouchEnd={onTouchEnd} style={itemHeightVarStyle} className={cn( 'date-picker-column h-[var(--popup-height)] overflow-clip relative', className )}> <div className="picker-positioner w-full absolute top-[calc(50%-var(--half-date-item-height))]"> <animated.ol style={springStyle} className="date-time-picker text-center"> {dateTimeList.map((dateTimeStr) => ( <li key={dateTimeStr} className="h-[var(--date-item-height)] leading-[var(--date-item-height)]"> {dateTimeStr} </li> ))} </animated.ol> </div> </div> ) }需要使用
useEffect监听dateTimeValue变化,重新计算currentDateIndex,然后重新setTranslateY同步
dateTimeValue变化时的滚动偏移量位置1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43export const DateTimeColumn: React.FC<ColumnProps> = ({ className, dateItemHeight = 36, dateTimeValue, dateTimeList, onChange, }) => { const halfDateItemHeight = dateItemHeight / 2 const itemHeightVarStyle = {/* ... */} const currentDateIndex = dateTimeList.indexOf(dateTimeValue) if (currentDateIndex === -1) {/* ... */} const [isTouching, setIsTouching] = useState(false) const [lastY, setLastY] = useState(-1) const [translateY, setTranslateYState] = useState(currentDateIndex * -dateItemHeight) const springStyle = useSpring({/* ... */}) const setTranslateY = (y: number) => { y = Math.min(0, y) y = Math.max(y, (dateTimeList.length - 1) * -dateItemHeight) setTranslateYState(y) } useEffect(() => { console.log('DateTimeColumn_______________________') console.log('%c⧭', 'color: #00ff88', dateTimeValue) console.log('_______________________DateTimeColumn') const currentDateIndex = dateTimeList.indexOf(dateTimeValue) setTranslateY(currentDateIndex * -dateItemHeight) }, [dateTimeValue]) // ... return ( <div onTouchStart={onTouchStart} onTouchMove={onTouchMove} onTouchEnd={onTouchEnd} style={itemHeightVarStyle} className={cn(/* ... */)}> {/* ... */} </div> ) }
4. 确定和取消按钮 ⇧
@/components/form/DatePickerPopup.tsx
|
|
- 将
onChange改为确认/取消交互
@/modules/items/input/DateInput.tsx
|
|
5. 修复数据共享引起的bug ⇧
``
|
|
参考文章
- 无
相关文章
- 无
- 作者: Joel
- 文章链接:
- 版权声明
- 非自由转载-非商用-非衍生-保持署名