antd3中InputNumber组件录入去尾四位小数并百分化展现的一种实现(react)

antd对应3.x版本,react对应非hooks写法,本文也对标一些关于“js小数乘除失精”的解决策略。

antd3的InputNumber数字输入框

业务要求:录入时的数字展示,是一个保留了两位小数的非负百分数(不用补零)-->分析:即真值为4位小数,多录的部分去尾。

jsx部分源码(table组件的column部分列配置):

            {
                dataIndex: 'col3',
                title: '费用',
                render: (text, record, index) => <span>

                        <InputNumber
                            disabled={mode === "read" || mode === "audit" ? true : handling}
                            defaultValue={Number(record.amtRate) * 10000 / 100}
                            formatter={value => {
                                if (value.toString().slice(-1)[0] === "." || value.toString().split(".")[1] === "0") {
                                    return `${value}`
                                } else {
                                    let decimal = value.toString().split(".")[1];//小数部分
                                    return decimal && decimal.length === 1 ? `${Math.floor(Number(value) * 10) / 10}` : `${Math.floor(Number(value) * 100) / 100}`
                                }


                            }}
                            parser={value => value}
                            min={0} step={0.01}
                            onChange={(value) => this.setState({
                                costList: costList.map(item => {
                                    if (item.front_id === record.front_id) {
                                        let decimal = value.toString().split(".")[1];//小数部分
                                        item.amtRate = decimal && decimal.length === 1 ? Math.floor(Number(value) * 10) / 1000 : Math.floor(Number(value) * 100) / 10000;

                                    }
                                    return item
                                })
                            })} />

                   
                    <b>%</b></span>
            },

源码讲解:

modehandling是两个结构自this.state的变量,前者判断页面状态("read"查看“audit”审查,二者均代表只读模式,开启disabled禁用),后者handling表示页面是否有接口在请求,若有则置为true即开启input的disabled禁用(因为有三目,所以非只读模式才会后这个判断)。

defaultValue这个props算是一个重点,通常情况下,笔者会用value来配合双绑,写成双绑好处是可控,而不用额外写点什么来“达到清空/重置”的效果。此处,笔者个人的总结,因为“业务限制”,不可使用双绑,所以使用了defaultValue。

赋值的时候我用了record.amtRate而非text,因为完整版的代码这块使用了一个三目来渲染了两个不同的InputNumber,即“行值中的col3不对应列名col3,在某种条件下使用行值的antRate来展示给col3这个列”。(因为是两个不同的组件对应两个不同的值,所以上述的"清空/重置"也不一定非要用双绑了)

也要注意一下,我这里的扩大一百倍的写法Number(record.amtRate) * 10000 / 100 ,“因为我知道是四位小数扩大一百倍,后面的数值我也会按照这个逻辑去限制”,所以我是 先乘10000(因为是四位小数)再除以100来达到的扩大100倍

不理解这块失精的,奈何笔者也没有什么很深刻的洞见,仅仅是知道如何去简便处理。失精的例子,可以看如下:

let a =0.33;

console.log(a*10);    // 3.3000000000000003 【不足以将所有小数位化整】

console.log(a*100);    //33 【刚好】

console.log(a*1000);    //330 【过大了】

console.log(a*1000/10);    //33 【把过大的一位除掉,也刚好了】<--这个思路,便是本文失精相关案例中笔者所常用的

`formatter和parser往后稍稍,我们随后再讲`

min是antd中数字输入框组件用来控制最小值的官方api,此处因为非负,所以最小值是0

step是antd中数字输入框组件用来控制“步长”的官方api(输入框左边不是有个上下小箭头,按一下上或下所变化的量就靠这个控制,键盘上下箭头也能触发)。这里我们需要转换一下思路

虽然真正的值是四位小数,但是我们看到的是一个“保留2位小数的非负百分数”,所以步长是0.01,而不是0.0001

onChange在官方文档的ts描述里参数为value: number | string,这段说是number或string,我们不知道拿到的是什么类型的值,所以计算前后得处理一下。

可以看到有个costList,这个state便是我用于table组件的dataSource赋值的。后面的item.front_id === record.front_id也就是匹配到jsonarray的指定index进行修改,不做过多说明。

let decimal = value.toString().split(".")[1];//小数部分
item.amtRate = decimal && decimal.length === 1 ? Math.floor(Number(value) * 10) / 1000 : Math.floor(Number(value) * 100) / 10000;

第一段代码,将value转成string类型,通过.分割成数组,数组下标为1的部分即是小数。(注:antd中,InputNumber的onChange所接受的值,已经剔除了“未输完的值”以及做了别的格式化。我们此处只要将两位小数去尾再变成四位小数即可。因为解除了双绑,除了这里对真值进行去尾,显示的值也要进行一次去尾,在formatter部分)

这里我用了一个三目,判断条件是decimal && decimal.length === 1

情况1:若出现了3.3,仅仅是一位小数,所以decimal.length===1,先Number化,然后乘以10,将整数化的值去尾,然后除以1000。【关于这里为什么要对一位小数特别对待,底层原理笔者也不是很清楚,但是确实不进行“刚好”处理便会再现失精,便用三目进行特殊化了

情况2:若出现了3.33,不满足decimal.length===1,所以数字化、乘以100、去尾、除以10000

特例:就算万一出现了没输完的5.但因为不满足&&前的decimal所以会进到后面*100/10000的逻辑。

 

对于formatterparser

前者是将输入值变成修改后的字符串再展示到页面,而后者是将修改后所展示的字符串还原回去

如果直接用这组属性在输入框里面显示%,本业务我们会有更多的操作要完善,所以我直接在输入框外面加了%,可以看到我的parser非常短,来啥返回啥,官方文档里是Function(value: number | string),所以就算我返回了string也会被强转成number。

formatter

value.toString().slice(-1)[0] === "." || value.toString().split(".")[1] === "0"

你们可以看到我在value后面都加了toString,以防过于好心“在某种条件下会塞给我number”,毕竟官方文档是function(value: number | string): string

.slice(-1)[0]这段,.slice(-1)就是浅拷贝一个数组取-1即最后一位变成一个新数组,旧数组-1位值即新数组第0位的值。如果末尾是"."即用户输入了"5."或者"6."这种可能没有输入完的值(也可能输完了,输完了就交给antd自行处理),不做处理直接原封不动的返回其字符串return `${value}`

.split(".")[1]这段,即判断用户是否是输入了"5.0"或者"6.0"这种可能没有输入完的值,比如完整值为5.01或者6.02,此时我们也return `${value}`

如果不是上述“可能没有输完”的情况,那就来把输入值转换一下。

这里我们理一理,用户输入了一个值,唤作输入值,输入值输入完后经过formatter进行了格式化展示,而后通过parser还原再塞给onChange,我们在onChange中转换成真值来更新state

let decimal = value.toString().split(".")[1];//小数部分
return decimal && decimal.length === 1 ? `${Math.floor(Number(value) * 10) / 10}` : `${Math.floor(Number(value) * 100) / 100}`

这段逻辑,和我们之前提过的很像,如果是一位小数,就乘10去尾再除10,如果是非一位小数,就乘100去尾再除以100 (比如整数,或更多位的小数)

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
可以通过设置 `formatter` 和 `parser` 属性来实现 Ant Design 的 `InputNumber` 组件限制金额为两小数。下面是一个示例代码: ```jsx import React, { useState } from 'react'; import { InputNumber } from 'antd'; const App = () => { const [value, setValue] = useState(0); const handleValueChange = (value) => { setValue(value); }; const handleFormatter = (value) => { return `¥ ${value.toFixed(2)}`; }; const handleParser = (value) => { return parseFloat(value.replace(/[^\d\.]/g, '')); }; return ( <InputNumber value={value} min={0} step={0.01} formatter={handleFormatter} parser={handleParser} onChange={handleValueChange} /> ); }; export default App; ``` 在这个示例代码,我们将 `formatter` 属性设置为一个函数,它接收一个数字类型的参数 `value`,并返回一个字符串类型的值。在这个函数,我们使用 `toFixed(2)` 方法来限制小数数为两,并在前面添加 `¥` 符号。 同时,我们将 `parser` 属性设置为一个函数,它接收一个字符串类型的参数 `value`,并返回一个数字类型的值。在这个函数,我们使用正则表达式将除了数字和小数点以外的字符替换为空字符串,并使用 `parseFloat` 方法将结果转换为数字类型。 最后,我们将 `min` 属性设置为 `0`,`step` 属性设置为 `0.01`,来限制最小值和步长。这样,我们就可以实现 Ant Design 的 `InputNumber` 组件限制金额为两小数的要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

devwolf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值