彻底搞懂 TDesign Vue Next 数字输入框 decimalPlaces 属性:从类型陷阱到最佳实践
你是否在使用 TDesign Vue Next 数字输入框时,遇到过 decimalPlaces 属性设置不生效的问题?或者对它同时支持 number 和 object 两种类型感到困惑?本文将从类型定义、实现原理到实战案例,全面解析 decimalPlaces 的设计逻辑与避坑指南,帮你彻底掌握这个高频使用却极易出错的属性。
一、属性类型解析:为什么 decimalPlaces 支持两种类型?
1.1 基础类型定义揭秘
TDesign Vue Next 数字输入框(InputNumber)的 decimalPlaces 属性在类型定义文件(type.ts)中被明确定义为联合类型:
// packages/components/input-number/type.ts 核心定义
export type InputNumberDecimalPlaces = number | {
enableRound: boolean; // 是否启用四舍五入
places: number; // 小数位数
};
这种设计源于实际开发中的两种常见需求:
- 简单场景:仅需指定固定小数位数(如保留2位小数)
- 复杂场景:需要精确控制四舍五入行为(如金融场景需截断而非四舍五入)
1.2 两种类型的本质区别
通过 props.ts 文件可以看到属性的校验逻辑:
// packages/components/input-number/props.ts 类型校验
decimalPlaces: {
type: [Number, Object] as PropType<TdInputNumberProps['decimalPlaces']>,
default: undefined as TdInputNumberProps['decimalPlaces'],
},
| 类型 | 适用场景 | 内部处理逻辑 |
|---|---|---|
| number | 快速设置小数位数,自动四舍五入 | 等价于 { enableRound: true, places: number } |
| object | 需要关闭四舍五入或动态调整舍入策略 | 显式控制四舍五入行为 |
二、实现原理:decimalPlaces 如何影响数值处理?
2.1 核心处理流程
从测试用例和组件源码可以推断出 decimalPlaces 的处理流程:
2.2 关键代码实现
虽然无法获取完整的格式化函数代码,但从测试用例可以反推出核心逻辑:
// 推断的格式化函数逻辑
function formatNumber(value, decimalPlaces) {
let { places, enableRound = true } =
typeof decimalPlaces === 'number'
? { places: decimalPlaces, enableRound: true }
: decimalPlaces;
if (enableRound) {
return Number(value).toFixed(places);
} else {
const [integerPart, decimalPart] = String(value).split('.');
return decimalPart
? `${integerPart}.${decimalPart.slice(0, places)}`
: integerPart;
}
}
三、实战指南:decimalPlaces 正确用法与避坑
3.1 基础用法:数字类型设置
最简单的保留指定位数小数(默认四舍五入):
<template>
<TInputNumber
v-model="price"
:decimal-places="2"
placeholder="保留两位小数"
/>
</template>
<script setup>
import { ref } from 'vue';
const price = ref(99.99); // 显示为 99.99
</script>
3.2 高级用法:对象类型精确控制
金融场景中常见的截断需求(不四舍五入):
<template>
<TInputNumber
v-model="amount"
:decimal-places="{ places: 2, enableRound: false }"
placeholder="截断至两位小数"
/>
</template>
<script setup>
import { ref } from 'vue';
const amount = ref(100.1234); // 显示为 100.12(而非四舍五入的 100.12)
</script>
3.3 大数场景特殊处理
当启用 largeNumber 模式时,decimalPlaces 仍正常工作:
<template>
<TInputNumber
v-model="largeValue"
:decimal-places="{ places: 0, enableRound: true }"
large-number
placeholder="大数四舍五入取整"
/>
</template>
<script setup>
import { ref } from 'vue';
const largeValue = ref("9999999999999999.5"); // 显示为 10000000000000000
</script>
四、避坑指南:常见问题与解决方案
4.1 类型错误导致不生效
问题表现:设置 decimalPlaces 后无任何效果
原因分析:误将对象属性名写错(如 place 而非 places)
解决方案:
// 错误示例
{ enableRound: false, place: 2 } // 属性名应为 places
// 正确示例
{ enableRound: false, places: 2 }
4.2 四舍五入与截断混淆
问题表现:需要精确截断却得到四舍五入结果
解决方案:显式设置 enableRound: false
<!-- 错误用法 -->
<TInputNumber :decimal-places="2" /> <!-- 自动四舍五入 -->
<!-- 正确用法 -->
<TInputNumber :decimal-places="{ places: 2, enableRound: false }" />
4.3 与 largeNumber 一起使用时的类型问题
问题表现:大数场景下小数位数设置失效
原因分析:大数模式下 value 必须为字符串类型
解决方案:
<TInputNumber
v-model="largeValue"
:decimal-places="2"
large-number
/>
<script setup>
const largeValue = ref("1234567890123456.789"); // 正确:字符串类型
// const largeValue = ref(1234567890123456.789); // 错误:数值类型会丢失精度
</script>
五、测试验证:确保 decimalPlaces 行为符合预期
5.1 单元测试关键用例
从 input-number.test.tsx 中提取的核心测试用例:
// 数值类型测试
it(':decimalPlaces', () => {
const value = ref('100');
const wrapper = mount(() => <InputNumber v-model={value.value} decimalPlaces={2} />);
const input = wrapper.find('.t-input input');
expect(input.element.value).toBe('100.00');
});
// 对象类型测试
it(':decimalPlaces: { enableRound: boolean }', () => {
const value3 = ref('1.356');
const wrapper3 = mount(() => (
<InputNumber v-model={value3.value} decimalPlaces={{ places: 2 }} />
));
expect(wrapper3.find('.t-input input').element.value).toBe('1.36'); // 四舍五入
const value4 = ref('1.356');
const wrapper4 = mount(() => (
<InputNumber v-model={value4.value} decimalPlaces={{ enableRound: false, places: 2 }} />
));
expect(wrapper4.find('.t-input input').element.value).toBe('1.35'); // 截断
});
5.2 手动测试 checklist
使用组件时建议验证以下场景:
- 小数位数为 0 时的整数处理
- 输入超过指定小数位的数字
- 负数场景下的小数处理
- 空值或 undefined 时的表现
- 与 max/min 限制同时使用的情况
六、最佳实践总结
6.1 类型选择决策指南
6.2 代码规范建议
- 明确类型注释:当使用 object 类型时添加详细注释
<TInputNumber
v-model="value"
:decimal-places="{
places: 2,
enableRound: false // 数值计算需精确截断,禁用四舍五入
}"
/>
- 统一配置管理:复杂场景下提取为常量
// constants.js
export const DECIMAL_CONFIG = {
MONEY: { places: 2, enableRound: true }, // 金额:保留2位小数并四舍五入
CALCULATION: { places: 4, enableRound: false }, // 计算:保留4位小数并截断
};
// 组件中使用
import { DECIMAL_CONFIG } from '@/constants';
<TInputNumber :decimal-places="DECIMAL_CONFIG.MONEY" />
- 结合 format 自定义格式化:复杂场景组合使用 decimalPlaces 和 format
<TInputNumber
v-model="value"
:decimal-places="2"
:format="(value) => `$${value}`"
/>
七、总结与展望
decimalPlaces 属性作为 TDesign Vue Next 数字输入框的核心功能,其双类型设计既满足了简单场景的快速使用,又提供了复杂场景的精确控制。通过本文的解析,相信你已经掌握了:
- decimalPlaces 两种类型的区别与应用场景
- 四舍五入与截断的实现原理
- 常见错误的识别与解决方法
- 符合工程化规范的最佳实践
在未来使用数字输入框时,建议根据实际业务场景选择合适的类型配置,并通过单元测试确保 decimalPlaces 行为符合预期。对于金融、计算等对精度要求极高的场景,务必结合 largeNumber 属性和字符串类型值使用,避免 JavaScript 数值精度问题带来的风险。
掌握 decimalPlaces,让你的数字输入交互既精准又优雅!
收藏本文,下次遇到数字输入框小数处理问题,直接对照指南快速解决!关注作者获取更多 TDesign 组件深度解析。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



