From f0d3786b4b8fee2bfccfadc931862a90279587c4 Mon Sep 17 00:00:00 2001 From: Manshu Tusker <35138018+dadaguai-git@users.noreply.github.com> Date: Sun, 8 Sep 2024 20:52:43 +0800 Subject: [PATCH] feat(Field): add min and max props (#13068) --- packages/vant/src/field/Field.tsx | 13 ++++++++++ packages/vant/src/field/README.md | 2 ++ packages/vant/src/field/README.zh-CN.md | 2 ++ packages/vant/src/field/test/index.spec.js | 28 ++++++++++++++++++++++ 4 files changed, 45 insertions(+) diff --git a/packages/vant/src/field/Field.tsx b/packages/vant/src/field/Field.tsx index 0d9742c12..d5beeb26a 100644 --- a/packages/vant/src/field/Field.tsx +++ b/packages/vant/src/field/Field.tsx @@ -27,6 +27,7 @@ import { makeNumericProp, createNamespace, type ComponentInstance, + clamp, } from '../utils'; import { cutString, @@ -81,6 +82,8 @@ export const fieldSharedProps = { autofocus: Boolean, clearable: Boolean, maxlength: numericProp, + max: Number, + min: Number, formatter: Function as PropType<(value: string) => string>, clearIcon: makeStringProp('clear'), modelValue: makeNumericProp(''), @@ -326,9 +329,19 @@ export default defineComponent({ const limitDiffLen = getStringLength(originalValue) - getStringLength(value); + // https://github.com/youzan/vant/issues/13058 if (props.type === 'number' || props.type === 'digit') { const isNumber = props.type === 'number'; value = formatNumber(value, isNumber, isNumber); + + if (trigger === 'onBlur' && value !== '') { + const adjustedValue = clamp( + +value, + props.min ?? -Infinity, + props.max ?? Infinity, + ); + value = adjustedValue.toString(); + } } let formatterDiffLen = 0; diff --git a/packages/vant/src/field/README.md b/packages/vant/src/field/README.md index bcd9955f5..76b522646 100644 --- a/packages/vant/src/field/README.md +++ b/packages/vant/src/field/README.md @@ -319,6 +319,8 @@ Use `label-align` prop to align the input value, can be set to `center`, `right` | type | Input type, support all [native types](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#input_types) and `digit` type | _FieldType_ | `text` | | size | Size, can be set to `large` `normal` | _string_ | - | | maxlength | Max length of value | _number \| string_ | - | +| min | When the input type is `number` or `digit`, set the minimum allowable value | \_number | - | +| max | When the input type is `number` or `digit`, set the maximum allowable value | \_number | - | | placeholder | Input placeholder | _string_ | - | | border | Whether to show inner border | _boolean_ | `true` | | disabled | Whether to disable field | _boolean_ | `false` | diff --git a/packages/vant/src/field/README.zh-CN.md b/packages/vant/src/field/README.zh-CN.md index 0e651e37f..daa2df561 100644 --- a/packages/vant/src/field/README.zh-CN.md +++ b/packages/vant/src/field/README.zh-CN.md @@ -348,6 +348,8 @@ export default { | type | 输入框类型, 支持原生 input 标签的所有 [type 属性](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/input#%3Cinput%3E_types),额外支持了 `digit` 类型 | _FieldType_ | `text` | | size | 大小,可选值为 `large` `normal` | _string_ | - | | maxlength | 输入的最大字符数 | _number \| string_ | - | +| min | 输入框类型为 `number` 或 `digit` 类型时设置可允许的最小值 | \_number | - | +| max | 输入框类型为 `number` 或 `digit` 类型时设置可允许的最大值 | \_number | - | | placeholder | 输入框占位提示文字 | _string_ | - | | border | 是否显示内边框 | _boolean_ | `true` | | disabled | 是否禁用输入框 | _boolean_ | `false` | diff --git a/packages/vant/src/field/test/index.spec.js b/packages/vant/src/field/test/index.spec.js index 2b057255c..5d5278639 100644 --- a/packages/vant/src/field/test/index.spec.js +++ b/packages/vant/src/field/test/index.spec.js @@ -95,6 +95,34 @@ test('should format input value when type is digit', () => { expect(wrapper.emitted('update:modelValue')[2][0]).toEqual('123'); }); +test('should limit input value based on min and max props', async () => { + const wrapper = mount(Field, { + props: { + type: 'number', + min: 2, + max: 10, + modelValue: '', + }, + }); + + const input = wrapper.find('input'); + + // Test input value less than min + await wrapper.setProps({ modelValue: '1' }); + await input.trigger('blur'); + expect(wrapper.emitted('update:modelValue')[0][0]).toEqual('2'); + + // Test input value greater than max + await wrapper.setProps({ modelValue: '15' }); + await input.trigger('blur'); + expect(wrapper.emitted('update:modelValue')[1][0]).toEqual('10'); + + // Test input value within range + input.element.value = '5'; + input.trigger('input'); + expect(wrapper.emitted('update:modelValue')[2][0]).toEqual('5'); +}); + test('should render textarea when type is textarea', async () => { const wrapper = mount(Field, { props: {