数字和大写中文实时互转,一个vue指令实现

609 阅读8分钟

说在前面

最近在做一个需求,需要在用户输入数字失焦后实时将数字转为大写中文,聚焦的时候将大写中文转为数字以便用户继续修改。这里我们可以封装一个通用指令来做转换,接下来就让我们一起来实现一个转换指令吧。

效果展示

体验地址

jyeontu.xyz/jvuewheel/#…

实现思路

1、数字转大写中文

首先我们需要先实现一个函数,将数字转为大写中文的形式。

(1)函数入参

const numberToChineseWords = (num, unit = "元", append = "整") => {...};
  • num

必出参数,默认值为 “元”,需要进行转换的数字。

  • unit

可选参数,默认值为 “元”,用于指定整数金额部分后面跟随的单位字符。通过设置这个参数,可以根据不同的业务场景或语言习惯需求来改变金额单位的显示,比如在某些特定财务报表中可能需要显示为 “圆” 等情况,就可以传入相应的字符作为该参数的值进行自定义。

  • append

可选参数,默认值为 “整”,用于在金额为整数时,在转换后的中文金额表述后面追加的字符。比如常见的整数金额书写规范中会添加 “整” 字表示没有小数部分,若不需要这个追加字符或者有其他业务特定的追加内容要求,可以通过修改该参数来实现。

(2)辅助常量

用于辅助完成数字到中文的转换。

// 汉字的数字
const cnNums = ["零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"];
// 基本单位
const cnIntRadice = ["", "拾", "佰", "仟"];
// 对应整数部分扩展单位
const cnIntUnits = ["", "万", "亿", "兆"];
// 对应小数部分单位
const cnDecUnits = ["角", "分", "毫", "厘"];
// 最大处理的数字
const maxNum = 9999999999999999.99;

(3)输入参数合法性检查与预处理

  • 首先对传入的 num 参数进行空字符串检查,如果为空,则直接返回空字符串,避免后续不必要的处理。

  • 若转换后的金额大于 maxNum,超出了函数能够合理处理的范围,同样返回空字符串,确保函数的稳定性和正确性。

  • 对于金额为 0 的特殊情况,直接按照设定的格式(使用默认或传入的 unit 和 append 参数)构建并返回对应的中文金额表示,如 “零元整”(默认参数情况)。

(4)整数部分转换逻辑

if (parseInt(integerNum, 10) > 0) {
    let zeroCount = 0;
    let IntLen = integerNum.length;
    for (let i = 0; i < IntLen; i++) {
        let n = integerNum[i];
        let p = IntLen - i - 1;
        let q = p / 4;
        let m = p % 4;
        if (n === "0") {
            zeroCount++;
        } else {
            if (zeroCount > 0) {
                chineseStr += cnNums[0];
            }
            // 归零
            zeroCount = 0;
            chineseStr += cnNums[parseInt(n)] + cnIntRadice[m];
        }
        if (m === 0 && zeroCount < 4) {
            chineseStr += cnIntUnits[q];
        }
    }
    chineseStr += unit;
}
  • 当整数部分数字(通过 parseInt(integerNum, 10) 判断)大于 0 时,进入一个循环来处理整数部分的每一位数字。
  • 在循环中,对于每一位数字,先获取其对应的数字字符 n,并计算该位数字在整个整数金额中的位置信息,包括距离个位的位数 p、所在的四位一组中的位置索引 m 以及对应的扩展单位层级 q
  • 如果当前位数字是 0,则记录连续 0 的个数 zeroCount,用于后续判断是否需要添加 “” 字来正确表示中文金额的读法。当遇到非0数字时,如果之前有连续的 0,则先在 chineseStr 中添加 “” 字进行合理的中文表述衔接,并将 zeroCount 归零。然后根据当前数字和对应的基本单位 cnIntRadice[m] 构建出如 “叁佰” 这样的部分金额表述添加到 chineseStr 中。此外,当当前位处于每四位一组的个位位置(即 m === 0)且连续 0 的个数小于 4 时,添加对应的扩展单位 cnIntUnits[q]chineseStr 中,例如添加 “”“亿” 等字。循环结束后,在 chineseStr 末尾添加 unit(即整数金额对应的单位字符)。

(5)小数部分转换逻辑

if (decimalNum !== "") {
    let decLen = decimalNum.length;
    for (let i = 0; i < decLen; i++) {
        let n = decimalNum[i];
        if (n !== "0") {
            chineseStr += cnNums[Number(n)] + cnDecUnits[i];
        }
    }
}

对于小数部分,如果 decimalNum 不为空字符串,说明存在小数金额需要转换。通过循环遍历小数部分的每一位数字,当数字不为 0 时,将对应的中文数字(通过 cnNums[Number(n)] 获取)和相应的小数单位(cnDecUnits[i])组合添加到 chineseStr 中,构建出小数金额的中文表示形式,比如将 0.34 中的 3 转换为 “叁角” 添加到字符串中。

(6)最终结果处理与返回

if (chineseStr === "") {
    chineseStr += cnNums[0] + unit + append;
} else if (decimalNum === "") {
    chineseStr += append;
}
return chineseStr;

最后,需要根据 chineseStr 的情况进行一些补充处理。如果 chineseStr 为空(可能是传入的金额为 0 且经过前面逻辑处理后为空字符串等情况),则按照设定的格式(使用 unitappend 参数)构建并返回对应的中文金额表示,如 “零元整”。如果小数部分 decimalNum 为空,表示金额是整数,就在 chineseStr 后面添加 append(默认是 “整” 字)。

(7)转换测试

  • 1024
numberToChineseWords(1024)
//壹仟零贰拾肆元整

  • 99999999
numberToChineseWords(99999999)
//玖仟玖佰玖拾玖万玖仟玖佰玖拾玖元整

  • 12345.6789
numberToChineseWords(12345.6789)
//壹万贰仟叁佰肆拾伍元陆角柒分捌毫玖厘

2、指令实现

export default {
    bind: function (el, binding) {
        const params = binding.value || {};
        const { unit = "", append = "" } = params;
        let originVal = el.innerText;
        if (el.innerHTML) {
            el.innerHTML = numberToChineseWords(el.innerText, unit, append);
        }
        el.addEventListener("focus", (event) => {
            event.target.value = originVal;
        });
        el.addEventListener("blur", (event) => {
            const value = event.target.value;
            originVal = value;
            event.target.value = numberToChineseWords(value, unit, append);
        });
    },
};

(1)参数解构与默认值设置

bind 函数中,首先通过 binding.value 获取指令绑定的值(通常是一个对象形式传递的参数),如果没有传递值,则默认为一个空对象,将其赋值给 params 变量。然后,从 params 对象中解构出 unitappend 参数,并分别设置了默认值为空字符串。这里的 unitappend 参数的含义与前面提到的 numberToChineseWords 函数中的对应参数一致,用于自定义中文大写金额中整数部分的单位以及整数金额后的追加字符

(2)获取原始文本内容与初始转换

接着,获取元素的原始文本内容 originVal,这个值用于后续在元素获取焦点时还原用户看到的原始数字金额,方便编辑。如果元素有 innerHTML(即元素内部包含文本内容),则直接调用前面定义的 numberToChineseWords 函数,将元素的 innerText(也就是当前显示的文本内容,这里假设是数字金额相关)按照传入的 unitappend 参数进行转换,将转换后的中文大写金额结果重新赋值给元素的 innerHTML,实现了初始加载时将数字金额转换为中文大写金额显示的功能。

(3)焦点事件处理

添加 focus 事件监听器,当元素获得焦点时,在对应的事件处理函数中,将事件目标(也就是当前元素)的 value 属性设置为之前保存的 originVal这样用户在点击输入框等操作使元素获得焦点时,能够看到原始的数字金额内容,便于进行修改编辑,保证了用户交互体验的连贯性和便捷性。

(4)失焦事件处理

添加 blur 事件监听器,当元素失去焦点时,在事件处理函数中,首先获取当前元素的 value 属性值(也就是用户编辑后的值),将其赋值给 originVal,以便后续再次操作时能基于最新的值进行还原等处理。然后,再次调用 numberToChineseWords 函数,将编辑后的 value 按照 unitappend 参数进行转换,将转换后的中文大写金额结果重新赋值给元素的 value 属性,实现了用户编辑完数字金额后,自动将其转换为中文大写金额进行显示的功能。

组件库

组件文档

目前该组件也已经收录到我的组件库,组件文档地址如下: jyeontu.xyz/jvuewheel/#…

组件内容

组件库中还有许多好玩有趣的组件,如:

  • 悬浮按钮
  • 评论组件
  • 词云
  • 瀑布流照片容器
  • 视频动态封面
  • 3D轮播图
  • web桌宠
  • 贡献度面板
  • 拖拽上传
  • 自动补全输入框
  • 图片滑块验证

等等……

组件库源码

组件库已开源到gitee,有兴趣的也可以到这里看看:gitee.com/zheng_yongt…

🌟觉得有帮助的可以点个star~

🖊有什么问题或错误可以指出,欢迎pr~

📬有什么想要实现的组件或想法可以联系我~

公众号

关注公众号『前端也能这么有趣』,获取更多有趣内容。

发送『组件库』获取源码

说在后面

🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。