Skip to content
Open
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
52 changes: 52 additions & 0 deletions packages/web-vue/components/input-number/__test__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,56 @@ describe('InputNumber', () => {
await input.trigger('blur');
expect(input.element.value).toBe('10');
});

test('init value with scientific notation', () => {
const wrapper1 = mount(InputNumber, {
props: {
defaultValue: 1.234e5,
},
});
expect(wrapper1.find('input').element.value).toBe('123400');

const wrapper2 = mount(InputNumber, {
props: {
defaultValue: -2.34e-5,
},
});
expect(wrapper2.find('input').element.value).toBe('-0.0000234');

const wrapper3 = mount(InputNumber, {
props: {
defaultValue: -0.000000000000000000001,
},
});
expect(wrapper3.find('input').element.value).toBe(
'-0.000000000000000000001'
);

const wrapper4 = mount(InputNumber, {
props: {
defaultValue: 10000000000000000000000,
},
});
expect(wrapper4.find('input').element.value).toBe(
'10000000000000000000000'
);

const wrapper5 = mount(InputNumber, {
props: {
defaultValue: -10000000000000000000000,
},
});
expect(wrapper5.find('input').element.value).toBe(
'-10000000000000000000000'
);
});

test('should handle very small numbers without scientific notation', () => {
const wrapper = mount(InputNumber, {
props: {
defaultValue: 0.00000001,
},
});
expect(wrapper.find('input').element.value).toBe('0.00000001');
});
});
3 changes: 2 additions & 1 deletion packages/web-vue/components/input-number/input-number.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Size } from '../_utils/constant';
import { useFormItem } from '../_hooks/use-form-item';
import { useSize } from '../_hooks/use-size';
import { getKeyDownHandler, KEYBOARD_KEY } from '../_utils/keyboard';
import { toFixed, toSafeString } from './utils';

type StepMethods = 'minus' | 'plus';

Expand Down Expand Up @@ -261,7 +262,7 @@ export default defineComponent({

const numString = mergedPrecision.value
? number.toFixed(mergedPrecision.value)
: String(number);
: toSafeString(number);
return props.formatter?.(numString) ?? numString;
};

Expand Down
48 changes: 48 additions & 0 deletions packages/web-vue/components/input-number/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import NP from 'number-precision';

/**
* Replace number.toFixed with Math.round
*/
export function toFixed(number: number, precision: number): string {
const pow = 10 ** precision;
return (Math.round(number * pow) / pow).toFixed(precision);
}

/**
* Convert number to non-scientific notation
*/
export function toSafeString(number: number | string): string {
// Use native Number.toString when it is NaN or non-scientific notation
const nativeNumberStr = number.toString();
if (Number.isNaN(+number) || !nativeNumberStr.includes('e')) {
return nativeNumberStr;
}

try {
const isNegative = number < 0;
const absoluteValue = Math.abs(+number);
// Get decimal length
const digitLength = NP.digitLength(absoluteValue);
// Convert decimal to integer
const integerNum = NP.float2Fixed(absoluteValue);
// Convert integer to non-scientific notation string
const integerStr = integerNum
.toString()
.replace(/e\+(\d+)/i, (_, $1) => new Array(+$1).fill(0).join(''));

return `${isNegative ? '-' : ''}${
digitLength === 0
? integerStr
: integerStr.replace(new RegExp(`\\d{1,${digitLength}}$`), (match) => {
const decimalStr = `${new Array(digitLength)
.fill(0)
.join('')}${match}`.slice(-digitLength);
return `${integerStr.length <= digitLength ? 0 : ''}.${decimalStr}`;
})
}`;
} catch (e) {
// If any error occurs, fallback to native string conversion
}

return nativeNumberStr;
}