mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
feat(components): [input-number] add disabled-scientific prop (#21319)
* feat(components): [input-number] add disableScientific prop * chore: useless change * Update basic.vue * Update basic.vue * Update docs/en-US/component/input-number.md Co-authored-by: Noblet Ouways <91417411+Dsaquel@users.noreply.github.com> * refactor: merge events * test: add test case * chore: tweaks * Update notes Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update docs/en-US/component/input-number.md Co-authored-by: btea <2356281422@qq.com> * chore: rename prop --------- Co-authored-by: Noblet Ouways <91417411+Dsaquel@users.noreply.github.com> Co-authored-by: Dsaquel <291874700n@gmail.com> Co-authored-by: sea <45450994+warmthsea@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: btea <2356281422@qq.com>
This commit is contained in:
@@ -99,28 +99,29 @@ input-number/with-prefix-suffix
|
||||
|
||||
### Attributes
|
||||
|
||||
| Name | Description | Type | Default |
|
||||
| --------------------------- | ------------------------------------------------ | --------------------------------------------- | ----------------------- |
|
||||
| model-value / v-model | binding value | ^[number] / ^[null] | — |
|
||||
| min | the minimum allowed value | ^[number] | Number.MAX_SAFE_INTEGER |
|
||||
| max | the maximum allowed value | ^[number] | Number.MIN_SAFE_INTEGER |
|
||||
| step | incremental step | ^[number] | 1 |
|
||||
| step-strictly | whether input value can only be multiple of step | ^[boolean] | false |
|
||||
| precision | precision of input value | ^[number] | — |
|
||||
| size | size of the component | ^[enum]`'large' \| 'default' \| 'small'` | default |
|
||||
| readonly ^(2.2.16) | same as `readonly` in native input | ^[boolean] | false |
|
||||
| disabled | whether the component is disabled | ^[boolean] | false |
|
||||
| controls | whether to enable the control buttons | ^[boolean] | true |
|
||||
| controls-position | position of the control buttons | ^[enum]`'' \| 'right'` | — |
|
||||
| name | same as `name` in native input | ^[string] | — |
|
||||
| aria-label ^(a11y) ^(2.7.2) | same as `aria-label` in native input | ^[string] | — |
|
||||
| placeholder | same as `placeholder` in native input | ^[string] | — |
|
||||
| id | same as `id` in native input | ^[string] | — |
|
||||
| value-on-clear ^(2.2.0) | value should be set when input box is cleared | ^[number] / ^[null] / ^[enum]`'min' \| 'max'` | — |
|
||||
| validate-event | whether to trigger form validation | ^[boolean] | true |
|
||||
| label ^(a11y) ^(deprecated) | same as `aria-label` in native input | ^[string] | — |
|
||||
| inputmode ^(2.10.3) | same as `inputmode` in native input | ^[string] | — |
|
||||
| align ^(2.10.5) | alignment for the inner input text | ^[enum]`'left' \| 'center' \| 'right'` | 'center' |
|
||||
| Name | Description | Type | Default |
|
||||
| ----------------------------- | ------------------------------------------------ | --------------------------------------------- | ----------------------- |
|
||||
| model-value / v-model | binding value | ^[number] / ^[null] | — |
|
||||
| min | the minimum allowed value | ^[number] | Number.MAX_SAFE_INTEGER |
|
||||
| max | the maximum allowed value | ^[number] | Number.MIN_SAFE_INTEGER |
|
||||
| step | incremental step | ^[number] | 1 |
|
||||
| step-strictly | whether input value can only be multiple of step | ^[boolean] | false |
|
||||
| precision | precision of input value | ^[number] | — |
|
||||
| size | size of the component | ^[enum]`'large' \| 'default' \| 'small'` | default |
|
||||
| readonly ^(2.2.16) | same as `readonly` in native input | ^[boolean] | false |
|
||||
| disabled | whether the component is disabled | ^[boolean] | false |
|
||||
| controls | whether to enable the control buttons | ^[boolean] | true |
|
||||
| controls-position | position of the control buttons | ^[enum]`'' \| 'right'` | — |
|
||||
| name | same as `name` in native input | ^[string] | — |
|
||||
| aria-label ^(a11y) ^(2.7.2) | same as `aria-label` in native input | ^[string] | — |
|
||||
| placeholder | same as `placeholder` in native input | ^[string] | — |
|
||||
| id | same as `id` in native input | ^[string] | — |
|
||||
| value-on-clear ^(2.2.0) | value should be set when input box is cleared | ^[number] / ^[null] / ^[enum]`'min' \| 'max'` | — |
|
||||
| validate-event | whether to trigger form validation | ^[boolean] | true |
|
||||
| label ^(a11y) ^(deprecated) | same as `aria-label` in native input | ^[string] | — |
|
||||
| inputmode ^(2.10.3) | same as `inputmode` in native input | ^[string] | — |
|
||||
| align ^(2.10.5) | alignment for the inner input text | ^[enum]`'left' \| 'center' \| 'right'` | 'center' |
|
||||
| disabled-scientific ^(2.10.5) | disables input of scientific notation (e.g. 'e') | ^[boolean] | false |
|
||||
|
||||
### Slots
|
||||
|
||||
|
||||
@@ -632,4 +632,30 @@ describe('InputNumber.vue', () => {
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
test('should prevent typing "e" or "E" when disabledScientific is true', async () => {
|
||||
const num = ref(1)
|
||||
const wrapper = mount(() => (
|
||||
<InputNumber v-model={num.value} disabledScientific />
|
||||
))
|
||||
const input = wrapper.find('input')
|
||||
const preventDefault = vi.fn()
|
||||
await input.trigger('keydown', {
|
||||
key: 'e',
|
||||
preventDefault,
|
||||
})
|
||||
expect(preventDefault).toHaveBeenCalled()
|
||||
preventDefault.mockClear()
|
||||
await input.trigger('keydown', {
|
||||
key: 'E',
|
||||
preventDefault,
|
||||
})
|
||||
expect(preventDefault).toHaveBeenCalled()
|
||||
preventDefault.mockClear()
|
||||
await input.trigger('keydown', {
|
||||
key: '1',
|
||||
preventDefault,
|
||||
})
|
||||
expect(preventDefault).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -127,6 +127,10 @@ export const inputNumberProps = buildProps({
|
||||
type: definePropType<'left' | 'right' | 'center'>(String),
|
||||
default: 'center',
|
||||
},
|
||||
/**
|
||||
* @description whether to disable scientific notation input (e.g. 'e', 'E')
|
||||
*/
|
||||
disabledScientific: Boolean,
|
||||
} as const)
|
||||
export type InputNumberProps = ExtractPropTypes<typeof inputNumberProps>
|
||||
export type InputNumberPropsPublic = __ExtractPublicPropTypes<
|
||||
|
||||
@@ -56,8 +56,7 @@
|
||||
:aria-label="ariaLabel"
|
||||
:validate-event="false"
|
||||
:inputmode="inputmode"
|
||||
@keydown.up.prevent="increase"
|
||||
@keydown.down.prevent="decrease"
|
||||
@keydown="handleKeydown"
|
||||
@blur="handleBlur"
|
||||
@focus="handleFocus"
|
||||
@input="handleInput"
|
||||
@@ -95,6 +94,7 @@ import {
|
||||
import { ArrowDown, ArrowUp, Minus, Plus } from '@element-plus/icons-vue'
|
||||
import {
|
||||
CHANGE_EVENT,
|
||||
EVENT_CODE,
|
||||
INPUT_EVENT,
|
||||
UPDATE_MODEL_EVENT,
|
||||
} from '@element-plus/constants'
|
||||
@@ -210,6 +210,24 @@ const ensurePrecision = (val: number, coefficient: 1 | -1 = 1) => {
|
||||
// Solve the accuracy problem of JS decimal calculation by converting the value to integer.
|
||||
return toPrecision(val + props.step * coefficient)
|
||||
}
|
||||
const handleKeydown = (event: Event) => {
|
||||
const e = event as KeyboardEvent
|
||||
if (props.disabledScientific && ['e', 'E'].includes(e.key)) {
|
||||
e.preventDefault()
|
||||
return
|
||||
}
|
||||
const keyHandlers = {
|
||||
[EVENT_CODE.up]: () => {
|
||||
e.preventDefault()
|
||||
increase()
|
||||
},
|
||||
[EVENT_CODE.down]: () => {
|
||||
e.preventDefault()
|
||||
decrease()
|
||||
},
|
||||
}
|
||||
keyHandlers[e.key]?.()
|
||||
}
|
||||
const increase = () => {
|
||||
if (props.readonly || inputNumberDisabled.value || maxDisabled.value) return
|
||||
const value = Number(displayValue.value) || 0
|
||||
|
||||
Reference in New Issue
Block a user