From 569cd7dceccb412fce0ec39782d88a4a02aff792 Mon Sep 17 00:00:00 2001 From: joylee Date: Tue, 23 Sep 2025 16:23:24 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix(datepicker):=20=E4=BC=98=E5=8C=96=20pic?= =?UTF-8?q?ker=20=E7=BB=84=E4=BB=B6=E7=8A=B6=E6=80=81=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E4=B8=8E=E4=BA=8B=E4=BB=B6=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 改进 getDerivedStateFromProps 中对 open 属性变化的判断逻辑 - componentDidUpdate 中增加 visible 状态一致性检查 - 修复 changeVisible 方法中重复设置状态的问题 --- src/components/datepicker/common/picker.js | 89 ++++++++++++++-------- 1 file changed, 58 insertions(+), 31 deletions(-) diff --git a/src/components/datepicker/common/picker.js b/src/components/datepicker/common/picker.js index c1d786139..61c00ffae 100644 --- a/src/components/datepicker/common/picker.js +++ b/src/components/datepicker/common/picker.js @@ -24,13 +24,11 @@ class Picker extends Component { this.state = { currentValue: value ? formatValue(displayNow(new Date(value)), this.format) : defaultTime, - id: Math.random() - .toString() - .replace('.', ''), + id: Math.random().toString().replace('.', ''), visible: open, style: {}, prevProps: props, - checkFlag: true // 校验输入的日期格式是否正确 + checkFlag: true, // 校验输入的日期格式是否正确 }; this.inpRef = createRef(); @@ -38,32 +36,46 @@ class Picker extends Component { this.containerRef = createRef(); - this.setYearChild = ref => { + this.setYearChild = (ref) => { this.yearChild = ref; }; - this.setYearMonthChild = ref => { + this.setYearMonthChild = (ref) => { this.yearMonthChild = ref; }; - this.setMonthDayChild = ref => { + this.setMonthDayChild = (ref) => { this.monthDayChild = ref; }; - this.setDateChild = ref => { + this.setDateChild = (ref) => { this.dateChild = ref; }; } static getDerivedStateFromProps(props, prevState) { const { prevProps } = prevState; + + // 如果是初始化状态(没有 prevProps) + if (!prevProps) { + return { + visible: props.open || false, + prevProps: props, + }; + } + const { open } = props; const { open: prevOpen } = prevProps; + // 只有当 open 属性真正发生变化时才更新状态 if (open !== prevOpen) { return { visible: open, - prevProps: props + prevProps: props, }; } - return null; + + // 更新 prevProps 但不改变 visible 状态 + return { + prevProps: props, + }; } componentDidMount() { @@ -76,12 +88,14 @@ class Picker extends Component { componentDidUpdate(prevProps) { const { value: prevValue, open: prevOpen } = prevProps; const { value, open } = this.props; - const { checkFlag } = this.state; + const { checkFlag, visible } = this.state; if (prevValue !== value) { const date = checkFlag && value ? displayNow(new Date(value)) : value; this.handleValueChange(date, false); } - if (prevOpen !== open) { + + // 只有当 open 属性发生变化且与当前 visible 状态不一致时才调用 changeVisible + if (prevOpen !== open && open !== visible) { this.changeVisible(open); } } @@ -114,7 +128,7 @@ class Picker extends Component { const { checkFlag } = this.state; const value = (output && checkFlag) || isClickBtn ? this.props.formatValue(output) : output || ''; this.setState({ - currentValue: value ? value.toString().replace(/-/g, '/') : '' + currentValue: value ? value.toString().replace(/-/g, '/') : '', }); if (isPop) { this.props.onChange(value); @@ -154,7 +168,7 @@ class Picker extends Component { return ; }; - popClick = evt => { + popClick = (evt) => { evt.stopPropagation(); if (evt.nativeEvent.stopImmediatePropagation) { evt.nativeEvent.stopImmediatePropagation(); @@ -162,7 +176,7 @@ class Picker extends Component { }; // 关闭时 校验输入的是否正确 - handleClick = e => { + handleClick = (e) => { const isClickPicker = this.containerRef.current.contains(e.target) || (this.popupRef.current && this.popupRef.current.contains(e.target)); const { checkFlag, visible, currentValue } = this.state; const { tempMode, formatValue } = this.props; @@ -188,14 +202,19 @@ class Picker extends Component { } }; - changeVisible = isVisible => { + changeVisible = (isVisible) => { + // 防止重复设置相同的状态 + if (this.state.visible === isVisible) { + return; + } + const { containerRef } = this; const { id } = this.state; const { containerEleClass, height, isAppendToBody, className } = this.props; if (isVisible && id) { this.setState({ - visible: true + visible: true, }); const style = this.positionPop(); @@ -209,7 +228,7 @@ class Picker extends Component { containerRef.current,
{this.renderMainPop()} -
+ , ); } @@ -229,7 +248,7 @@ class Picker extends Component { } this.setState({ - visible: false + visible: false, }); this.props.onClose(); destroyDOM(id, containerRef.current); @@ -248,18 +267,18 @@ class Picker extends Component { position: 'fixed', left: isLocationAlignRight ? `${left - (POPUP_WIDTH - width)}px` : `${left}px`, top: isLocationTop ? `${top - popupHeight}px` : `${bottom}px`, - marginTop + marginTop, }; } return { top: isLocationTop ? `${-popupHeight}px` : `${height}px`, left: isLocationAlignRight ? '' : '0px', right: isLocationAlignRight ? '0px' : '', - marginTop + marginTop, }; }; - onClickInput = e => { + onClickInput = (e) => { e.stopPropagation(); const { disabled } = this.props; const { visible } = this.state; @@ -291,9 +310,8 @@ class Picker extends Component { currentValueTemp.length > lenRule || currentValueTemp.split('/').length > backslashRule + 1 ? currentValue.toString() : currentValueTemp; this.setState({ - currentValue: currentValueFinal + currentValue: currentValueFinal, }); - // 值改变的时候,日历要显示出来 if (!this.state.visible && currentValueFinal) { this.changeVisible(true); @@ -303,7 +321,7 @@ class Picker extends Component { const checkFlag = currentValueFinal ? checkFormat(currentValueFinal.trim(), tempMode, showTimePicker) : true; this.setState({ - checkFlag + checkFlag, }); // 校验通过 并且有值 日历选择联动 @@ -318,7 +336,16 @@ class Picker extends Component { const afterV = currentValueFinal.trim().split(' ')[1]; // 拿到年月日时分秒的数值 const dealData = transformObj(currentValueFinal); // hour: 'other', minute: 'other', second: 'other' 方式時分秒重置,具體看date-picker/grid.js配合使用 - this.dateChild.changeCheckValue(afterV ? dealData : { ...dealData, hour: 'other', minute: 'other', second: 'other' }); + this.dateChild.changeCheckValue( + afterV + ? dealData + : { + ...dealData, + hour: 'other', + minute: 'other', + second: 'other', + }, + ); // this.dateChild.changeCheckValue( afterV ? dealData : { ...dealData, hour: null, minute: null, second: null } ); } } @@ -354,7 +381,7 @@ class Picker extends Component { // 校验年月日格式是否正确,正确 补全 校验设置为true;不正确 不补全 returnValue = this.props.formatValue(transformObj(formatValue(displayNow(new Date(`${currentValue.trim()} ${defaultTime}`)), this.format))); this.setState({ - currentValue: returnValue + currentValue: returnValue, }); } @@ -381,7 +408,7 @@ class Picker extends Component { 'minDate', 'tempMode', 'formatValue', - 'integer' + 'integer', ]); return ( @@ -409,7 +436,7 @@ class Picker extends Component {
{this.renderMainPop()}
, - this.portal + this.portal, )} ); @@ -427,7 +454,7 @@ Picker.propTypes = { formatValue: PropTypes.func, onChange: PropTypes.func, onClose: PropTypes.func, - canEdit: PropTypes.bool + canEdit: PropTypes.bool, }; Picker.defaultProps = { @@ -441,7 +468,7 @@ Picker.defaultProps = { formatValue: noop, onChange: noop, onClose: noop, - canEdit: false + canEdit: false, }; export default Picker; From 9967d061bdaa25a4cc02d52b9d5dfc5323b32f80 Mon Sep 17 00:00:00 2001 From: joylee Date: Wed, 24 Sep 2025 17:05:16 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix(datepicker):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E6=97=A5=E6=9C=9F=E9=80=89=E6=8B=A9=E5=99=A8=E9=9D=A2=E6=9D=BF?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/datepicker/common/picker.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/datepicker/common/picker.js b/src/components/datepicker/common/picker.js index 61c00ffae..0e4e249dc 100644 --- a/src/components/datepicker/common/picker.js +++ b/src/components/datepicker/common/picker.js @@ -285,9 +285,15 @@ class Picker extends Component { if (disabled) return; - // 如果不可见则显示面板 + // 修复:无论面板是否可见,都重新激活它以确保正确显示 if (!visible) { this.changeVisible(true); + } else { + // 先关闭再打开,确保面板能正确响应 + this.changeVisible(false); + setTimeout(() => { + this.changeVisible(true); + }, 10); } };