Skip to content

fix: 解决InputNumber数字输入框,去除掉值之后失焦/确认之后会变成数值0的问题。 #1849

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/devui-vue/devui/breadcrumb/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export const getPropsSlot = (slots, props, prop = 'default') => {
export const getPropsSlot = (slots: any, props: any, prop = 'default') => {
return props[prop] ?? slots[prop]?.();
};
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export default defineComponent({
<d-input
v-model={formData.text}
autocomplete='off'
autofocus
maxlength={tag.value.maxLength}
placeholder={tag.value.placeholder || ''}></d-input>
</d-form-item>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,3 +279,20 @@ describe('d-input-number', () => {
expect(selectFn).toBeCalledTimes(2);
});
});


it('allowEmpty', async () => {
const num = ref();
const wrapper = mount({
setup() {
return () => <DInputNumber v-model={num.value} allowEmpty={true} ></DInputNumber>;
},
});
num.value = undefined;
const inputInner = wrapper.find(ns.e('input-box'));
expect((inputInner.element as HTMLInputElement).value).toBeNull;
num.value = 51;
expect((inputInner.element as HTMLInputElement).value).toBe('51');
num.value = '';
expect((inputInner.element as HTMLInputElement).value).toBeNull;
});
2 changes: 1 addition & 1 deletion packages/devui-vue/devui/input-number/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ export default {
category: '数据录入',
status: '50%',
install(app: App): void {
app.component(InputNumber.name, InputNumber);
app.component(InputNumber.name as string, InputNumber);
}
};
16 changes: 10 additions & 6 deletions packages/devui-vue/devui/input-number/src/input-number-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import type { PropType, ExtractPropTypes, ComputedRef, Ref, CSSProperties, Input
export type ISize = 'lg' | 'md' | 'sm';

export const inputNumberProps = {
modelValue: {
type: [Number, String] as PropType<number | string | null | undefined>,
},
placeholder: {
type: String,
},
Expand All @@ -25,9 +28,6 @@ export const inputNumberProps = {
size: {
type: String as PropType<ISize>,
},
modelValue: {
type: Number,
},
precision: {
type: Number,
},
Expand All @@ -39,13 +39,17 @@ export const inputNumberProps = {
type: Boolean,
default: true,
},
allowEmpty: {
type: Boolean,
default: false,
}
} as const;

export type InputNumberProps = ExtractPropTypes<typeof inputNumberProps>;

export interface IState {
currentValue: number | string | undefined;
userInputValue: number | string | undefined;
currentValue: number | string | undefined | null;
userInputValue: number | string | undefined | null;
}

export interface UseExpose {
Expand All @@ -62,7 +66,7 @@ export interface UseRender {
}

export interface UseEvent {
inputVal: ComputedRef<number | string | undefined>;
inputVal: ComputedRef<number | string | undefined | null>;
minDisabled: ComputedRef<boolean>;
maxDisabled: ComputedRef<boolean>;
onAdd: () => void;
Expand Down
28 changes: 13 additions & 15 deletions packages/devui-vue/devui/input-number/src/use-input-number.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import { computed, reactive, toRefs, watch, ref, inject } from 'vue';
import { computed, reactive, toRefs, watch, ref, inject, InjectionKey } from 'vue';
import type { SetupContext, Ref, CSSProperties } from 'vue';
import { InputNumberProps, UseEvent, UseRender, IState, UseExpose } from './input-number-types';
import { useNamespace } from '../../shared/hooks/use-namespace';
import { isNumber, isUndefined } from '../../shared/utils';
import { FORM_TOKEN } from '../../form';
import { FORM_TOKEN, type FormProps } from '../../form';

const ns = useNamespace('input-number');

export function useRender(props: InputNumberProps, ctx: SetupContext): UseRender {
const formContext = inject(FORM_TOKEN, undefined);
const formContext: FormProps | undefined | any = inject(FORM_TOKEN, undefined); // 修复ts语法错误组件不被d-from组件引用时,formContext未被定义
const { style, class: customClass, ...otherAttrs } = ctx.attrs;
const customStyle = { style: style as CSSProperties };

const inputNumberSize = computed(() => props.size || formContext?.size || 'md');

const wrapClass = computed(() => [
Expand Down Expand Up @@ -56,12 +55,12 @@ export function useExpose(ctx: SetupContext): UseExpose {
return { inputRef };
}

function getPrecision(pre: number | undefined): number {
function getPrecision(pre: string | number | undefined | null): number {
let precision = 0;
if (isUndefined(pre)) {
return precision;
}
const preString = pre.toString();
const preString = (pre as string).toString();
const dotIndex = preString.indexOf('.');
if (dotIndex !== -1) {
precision = preString.length - dotIndex - 1;
Expand Down Expand Up @@ -89,8 +88,8 @@ export function useEvent(props: InputNumberProps, ctx: SetupContext, inputRef: R
return state.userInputValue;
}
let currentValue = state.currentValue;
if (currentValue === '' || isUndefined(currentValue) || Number.isNaN(currentValue)) {
return '';
if (!currentValue && currentValue !== 0) {
return null;
}
if (isNumber(currentValue)) {
// todo 小数精度 确认是否应该以正则处理
Expand All @@ -111,17 +110,16 @@ export function useEvent(props: InputNumberProps, ctx: SetupContext, inputRef: R
};

const correctValue = (value: number | string | undefined | null) => {
if ((!value && value !== 0) && props.allowEmpty) { // 当用户开始允许空值时 value不为0的false全返回null(即'',null,undefined,NaN都会反回null设计与dev_ui_ag版本一致)
return null;
}
// 校验正则
const valueStr = value + '';
if (props.reg && !valueStr.match(new RegExp(props.reg))) {
return undefined;
}

let newVal = Number(value);
// 不是0 是假值或者是NaN返回undefined
if (newVal !== 0 && (!Number(value) || Number.isNaN(newVal))) {
return undefined;
}

// 精度限制存在才做转换
if (!isUndefined(props.precision)) {
Expand All @@ -135,14 +133,14 @@ export function useEvent(props: InputNumberProps, ctx: SetupContext, inputRef: R
return newVal;
};

const setCurrentValue = (value: number | string | undefined) => {
const setCurrentValue = (value: number | string | undefined | null) => {
const oldVal = state.currentValue;
const newVal = correctValue(value);

state.userInputValue = undefined;

// 0 可以被更新
if (newVal !== 0 && !newVal) {
// 0 和 '' 可以被更新
if (newVal !== 0 && newVal !== null && !newVal) {
ctx.emit('update:modelValue', oldVal);
return;
}
Expand Down
33 changes: 32 additions & 1 deletion packages/devui-vue/docs/components/input-number/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,36 @@ export default defineComponent({

:::

### 允许空值

:::demo 当 `allowEmpty` 为 `true` 的时候允许输入框的值为空,空值返回为 `null`,传入数据不为 `number` 类型且上一次输入没有值的时候都会返回null。

```vue
<template>
<div>
<d-input-number v-model="num" :allowEmpty="true" @change="onChange"></d-input-number>
</div>
</template>
<script>
import { defineComponent, ref } from 'vue';

export default defineComponent({
setup(props) {
const num = ref(undefined);
const onChange = (newVal, oldVal) => {
console.log(newVal, oldVal);
};
return {
num,
onChange
};
}
})
</script>
```

:::

### InputNumber 参数

| 参数名 | 类型 | 默认值 | 说明 | 跳转 Demo |
Expand All @@ -235,7 +265,8 @@ export default defineComponent({
| disabled | `boolean` | false | 可选,文本框是否被禁用 | [禁用状态](#禁用状态) |
| precision | `number` | -- | 可选,数值精度 | [精度](#精度) |
| size | [ISize](#isize) | 'md' | 可选,文本框尺寸 | [尺寸](#尺寸) |
| reg | `RegExp\| string` | -- | 可选,用于限制输入的正则或正则字符串 | [正则限制](#正则限制)|
| reg | `RegExp \| string` | -- | 可选,用于限制输入的正则或正则字符串 | [正则限制](#正则限制)|
| allowEmpty | `boolean \| false` | -- | 可选,是否允许值为空 允许空值 | [允许空值](#允许空值) |
|show-glow-style|`boolean`|true|可选,是否展示悬浮发光效果||

### InputNumber 事件
Expand Down
Loading