From 4c20ed7126ba3f36c7d0755353b7399eb3666913 Mon Sep 17 00:00:00 2001 From: "Alex.huxiyang" <1872591453@qq.com> Date: Fri, 2 Aug 2024 18:44:30 +0800 Subject: [PATCH] fix(inputNumber): correct onChange, onOverlimit event triggering timing when async & sync (#2509) * fix(inputNumber): onOverlimit and onchange * fix(inputNumber): onOverlimit and onchange * chore: unify demo * chore: add test * chore: add test * fix: not overlimit * fix: reset demo * fix: test --- .../__tests__/inputnumber.spec.tsx | 17 +++++++ src/packages/inputnumber/demos/h5/demo3.tsx | 12 ++++- src/packages/inputnumber/demos/h5/demo8.tsx | 15 ++++++- src/packages/inputnumber/demos/taro/demo3.tsx | 3 ++ src/packages/inputnumber/demos/taro/demo8.tsx | 13 +++++- src/packages/inputnumber/inputnumber.taro.tsx | 45 ++++++++++++++----- src/packages/inputnumber/inputnumber.tsx | 43 +++++++++++++----- 7 files changed, 123 insertions(+), 25 deletions(-) diff --git a/src/packages/inputnumber/__tests__/inputnumber.spec.tsx b/src/packages/inputnumber/__tests__/inputnumber.spec.tsx index eb770e5734..606fec2100 100644 --- a/src/packages/inputnumber/__tests__/inputnumber.spec.tsx +++ b/src/packages/inputnumber/__tests__/inputnumber.spec.tsx @@ -157,3 +157,20 @@ test('allowEmpty', () => { expect(container.querySelector('input')?.value).toBe('') }) }) + +test('should overlimit when input', () => { + const change = vi.fn() + const overlimit = vi.fn() + const { container } = render( + + ) + const input = container.querySelectorAll('input')[0] + input.value = '200' + fireEvent.input(input) + expect(change).toBeCalled() +}) diff --git a/src/packages/inputnumber/demos/h5/demo3.tsx b/src/packages/inputnumber/demos/h5/demo3.tsx index 8fcf1e3a68..2790c69244 100644 --- a/src/packages/inputnumber/demos/h5/demo3.tsx +++ b/src/packages/inputnumber/demos/h5/demo3.tsx @@ -2,11 +2,19 @@ import React from 'react' import { InputNumber, Toast } from '@nutui/nutui-react' const Demo3 = () => { - const overlimit = () => { + const overlimit = (e: any) => { Toast.show({ content: '超出限制事件触发', icon: 'warn' }) } return ( - + { + console.log('onChange', v) + }} + /> ) } export default Demo3 diff --git a/src/packages/inputnumber/demos/h5/demo8.tsx b/src/packages/inputnumber/demos/h5/demo8.tsx index fc9c270ad7..e66949dddf 100644 --- a/src/packages/inputnumber/demos/h5/demo8.tsx +++ b/src/packages/inputnumber/demos/h5/demo8.tsx @@ -3,13 +3,26 @@ import { InputNumber, Toast } from '@nutui/nutui-react' const Demo8 = () => { const [inputValue, setInputValue] = useState(0) + const overlimit = (e: any) => { + console.log('超出限制事件触发', e) + } const onChange = (value: string | number) => { Toast.show({ icon: 'loading', content: '异步演示2秒后更改' }) + console.log('onChange', value) setTimeout(() => { setInputValue(Number(value)) Toast.clear() }, 2000) } - return + return ( + + ) } export default Demo8 diff --git a/src/packages/inputnumber/demos/taro/demo3.tsx b/src/packages/inputnumber/demos/taro/demo3.tsx index 61b92cb9b0..e3864406eb 100644 --- a/src/packages/inputnumber/demos/taro/demo3.tsx +++ b/src/packages/inputnumber/demos/taro/demo3.tsx @@ -22,6 +22,9 @@ const Demo3 = () => { min={10} max={20} onOverlimit={overlimit} + onChange={(v) => { + console.log('onChange', v) + }} /> { SetToastType(type) SetShow(true) } + const overlimit = (e: any) => { + console.log('超出限制事件触发', e) + } const onChange = (value: string | number) => { toastShow('异步演示 2 秒后更改', 'loading') + console.log('onChange', value) setTimeout(() => { setInputValue(Number(value)) SetShow(false) @@ -21,7 +25,14 @@ const Demo8 = () => { } return ( <> - + string onPlus: (e: React.MouseEvent) => void onMinus: (e: React.MouseEvent) => void - onOverlimit: (e: React.MouseEvent) => void + onOverlimit: (e: React.MouseEvent | ChangeEvent) => void onBlur: (e: React.FocusEvent) => void onFocus: (e: React.FocusEvent) => void onChange: ( @@ -181,7 +181,25 @@ export const InputNumber: FunctionComponent< if (text === '-') return null return text } - const handleInputChange = (e: React.ChangeEvent) => { + const clampValue = (valueStr: string | null) => { + if (valueStr === null) return defaultValue + const val = Number(parseFloat(valueStr || '0').toFixed(digits)) + return Math.max(Number(min), Math.min(Number(max), val)) + } + const handleValueChange = ( + valueStr: string | null, + e: React.ChangeEvent + ) => { + const val = clampValue(valueStr) + // input暂不触发onOverlimit + // if (val !== Number(e.target.value)) { + // onOverlimit?.(e) + // } + if (val !== Number(shadowValue)) { + onChange?.(val, e) + } + } + const handleInputChange = (e: ChangeEvent) => { // 设置 input 值, 在 blur 时格式化 setInputValue(e.target.value) const valueStr = parseValue(e.target.value) @@ -192,11 +210,9 @@ export const InputNumber: FunctionComponent< setShadowValue(defaultValue) } } else { - setShadowValue(valueStr as any) - } - if (!async) { - onChange?.(parseFloat(valueStr || '0').toFixed(digits) as any, e) + setShadowValue(clampValue(valueStr) as any) } + !async && handleValueChange(valueStr, e) } const handleFocus = (e: React.FocusEvent) => { setFocused(true) @@ -205,15 +221,22 @@ export const InputNumber: FunctionComponent< ? bound(Number(shadowValue), Number(min), Number(max)).toString() : '' ) - onFocus && onFocus(e) + onFocus?.(e) } const handleBlur = (e: React.FocusEvent) => { setFocused(false) - onBlur && onBlur(e) - if (async) { - const valueStr = parseValue(e.target.value) - onChange?.(parseFloat(valueStr || '0').toFixed(digits) as any, e) + onBlur?.(e) + const valueStr = parseValue(e.target.value) + if (valueStr === null) { + if (allowEmpty) { + setShadowValue(null) + } else { + setShadowValue(defaultValue) + } + } else { + setShadowValue(clampValue(valueStr) as any) } + async && handleValueChange(valueStr, e) } return ( diff --git a/src/packages/inputnumber/inputnumber.tsx b/src/packages/inputnumber/inputnumber.tsx index 45cfe6ae01..9c1dcee620 100644 --- a/src/packages/inputnumber/inputnumber.tsx +++ b/src/packages/inputnumber/inputnumber.tsx @@ -24,7 +24,7 @@ export interface InputNumberProps extends BasicComponent { formatter?: (value?: string | number) => string onPlus: (e: React.MouseEvent) => void onMinus: (e: React.MouseEvent) => void - onOverlimit: (e: React.MouseEvent) => void + onOverlimit: (e: React.MouseEvent | ChangeEvent) => void onBlur: (e: React.FocusEvent) => void onFocus: (e: React.FocusEvent) => void onChange: ( @@ -177,6 +177,24 @@ export const InputNumber: FunctionComponent< if (text === '-') return null return text } + const clampValue = (valueStr: string | null) => { + if (valueStr === null) return defaultValue + const val = Number(parseFloat(valueStr || '0').toFixed(digits)) + return Math.max(Number(min), Math.min(Number(max), val)) + } + const handleValueChange = ( + valueStr: string | null, + e: React.ChangeEvent + ) => { + const val = clampValue(valueStr) + // input暂不触发onOverlimit + // if (val !== Number(e.target.value)) { + // onOverlimit?.(e) + // } + if (val !== Number(shadowValue)) { + onChange?.(val, e) + } + } const handleInputChange = (e: React.ChangeEvent) => { // 设置 input 值, 在 blur 时格式化 setInputValue(e.target.value) @@ -188,11 +206,9 @@ export const InputNumber: FunctionComponent< setShadowValue(defaultValue) } } else { - setShadowValue(valueStr as any) - } - if (!async) { - onChange?.(parseFloat(valueStr || '0').toFixed(digits) as any, e) + setShadowValue(clampValue(valueStr) as any) } + !async && handleValueChange(valueStr, e) } const handleFocus = (e: React.FocusEvent) => { setFocused(true) @@ -201,15 +217,22 @@ export const InputNumber: FunctionComponent< ? bound(Number(shadowValue), Number(min), Number(max)).toString() : '' ) - onFocus && onFocus(e) + onFocus?.(e) } const handleBlur = (e: React.FocusEvent) => { setFocused(false) - onBlur && onBlur(e) - if (async) { - const valueStr = parseValue(e.target.value) - onChange?.(parseFloat(valueStr || '0').toFixed(digits) as any, e) + onBlur?.(e) + const valueStr = parseValue(e.target.value) + if (valueStr === null) { + if (allowEmpty) { + setShadowValue(null) + } else { + setShadowValue(defaultValue) + } + } else { + setShadowValue(clampValue(valueStr) as any) } + async && handleValueChange(valueStr, e) } return (