记录自用封装了一个货币组件

126 阅读3分钟

最近有个需求是封装一个货币组件,翻了下网上+自己结合封装了一个简陋版的,包含可控制小数位,鼠标移入显示大写金额,格式化金额展示等功能。 项目是vue2 + ant Design Vue 1.7.8版本

  1. utils下新建一个numToCny.js文件夹;
  2. 数字转换,暴露方法
// 数字金额转大写
export const numToCny=(money)=>{
	// 汉字的数字
	var cnNums = new Array('零', '壹', '贰', '叁', '肆', '伍', '陆',
	    '柒', '捌', '玖');
	// 基本单位
	var cnIntRadice = new Array('', '拾', '佰', '仟');
	// 对应整数部分扩展单位
	var cnIntUnits = new Array('', '万', '亿', '兆');
	// 对应小数部分单位
	var cnDecUnits = new Array('角', '分', '毫', '厘');
	// 整数金额时后面跟的字符
	var cnInteger = '整';
	// 整型完以后的单位
	var cnIntLast = '元';
	// 最大处理的数字
	var maxNum = 999999999999999.9999;
	// 金额整数部分
	var integerNum;
	// 金额小数部分
	var decimalNum;
	// 输出的中文金额字符串
	var chineseStr = '';
	// 分离金额后用的数组,预定义
	var parts;
	if (money == '') {
	    return '';
	}
	money = parseFloat(money);
	if (money >= maxNum) {
	    // 超出最大处理数字
	    return '';
	}
	if (money == 0) {
	    chineseStr = cnNums[0] + cnIntLast + cnInteger;
	    return chineseStr;
	}
	// 转换为字符串
	money = money.toString();
	if (money.indexOf('.') == -1) {
	    integerNum = money;
	    decimalNum = '';
	} else {
	    parts = money.split('.');
	    integerNum = parts[0];
	    decimalNum = parts[1].substr(0, 4);
	}
	// 获取整型部分转换
	if (parseInt(integerNum, 10) > 0) {
	    var zeroCount = 0;
	    var IntLen = integerNum.length;
	    for (var i = 0; i < IntLen; i++) {
	        var n = integerNum.substr(i, 1);
	        var p = IntLen - i - 1;
	        var q = p / 4;
	        var 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 += cnIntLast;
	}
	// 小数部分
	if (decimalNum != '') {
	    var decLen = decimalNum.length;
	    for (var i = 0; i < decLen; i++) {
	        var n = decimalNum.substr(i, 1);
	        if (n != '0') {
	            chineseStr += cnNums[Number(n)] + cnDecUnits[i];
	        }
	    }
	}
	if (chineseStr == '') {
	    chineseStr += cnNums[0] + cnIntLast + cnInteger;
	} else if (decimalNum == '') {
	    chineseStr += cnInteger;
	}
	return chineseStr;
}

3.在组件中调用;

<!--
 * @Description: 货币组件
-->
<template>
    <div>
        <a-tooltip :title="numToCny(this.value)" :get-popup-container="getPopupContainer">
            <a-input
                :value="formattedValue"
                :prefix="record.options.prefix"
                :suffix="record.options.suffix"
                :placeholder="record.options.placeholder"
                :disable="record.options.disable"
                @input="handleInput"
            />
        </a-tooltip>
    </div>
</template>

<script>
    import { numToCny } from '@/utils/numToCny';
    export default {
        props: {
            record: {
                type: Object,
            },
            value: {
                type: [Number, String],
            },
            decimalNumber: {
                type: Number,
            }
        },
        computed: {
            formattedValue() {
                // 将值转换为字符串
                let strValue = String(this.value);
                // 正则表达式校验和替换
                strValue = strValue.replace(/[^0-9.]/g, '');
                // 根据小数点将值分割为整数部分和小数部分
                const parts = strValue.split('.');
                // 格式化整数部分,每三位添加逗号分隔符
                parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
                // 重新组合整数部分和小数部分
                strValue = parts.join('.');
                return strValue;
            },
        },
        methods: {
            getPopupContainer(trigger) {
                return trigger.parentElement;
            },
            handleInput(event) {
                // 移除逗号分隔符
                const inputValue = event.target.value.replace(/,/g, '');
                // 使用正则表达式限制小数点后的最大输入长度
                const regex = new RegExp(`^(\\d+\\.?\\d{0,${this.decimalNumber}})?$`);
                const isValid = regex.test(inputValue);
                if (isValid) {
                    this.$emit('change', inputValue);
                } else {
                    // 如果输入不合法,将值重置为之前的值
                    this.$emit('change', this.value);
                }
            },
        },
    }
</script>

<style lang="scss" scoped>

</style>

4.父组件引用

<!-- 货币组件 -->
    <CurrencyComponent
      :record="record"  // 我这里是将所有参数整合到了record里面
      :value="record.options.defaultValue"
      :decimalNumber="record.options.decimalNumber"
      @change="(e) => {	handleChange(e, record.model)}"
      v-decorator="[
        record.model, // input 的 name
        {
          initialValue: record.options.defaultValue, // 默认值
          ruleCode: record.options.ruleCode,
          rules: record.rules, // 验证规则
        },]"
    />
    
    // 下面是对于record参数的定义,可以根据自己需求拆分成单独的props
    {
    label: "货币组件",
    type: "currency",
    icon: "transaction",
    options: {
      width: "100%", // 宽度
      defaultValue: '', // 默认值
      prefix: '¥',
      suffix: '人民币',
      decimalNumber: 2, // 小数点位数
      placeholder: "请输入金额",
      disabled: false, // 是否禁用,false不禁用,true禁用
      hidden: false,
      colCountKey: 24, // 表单栅格
      ifLineFeed: 'horizontal', // 组件布局
      helpTips: '', // 帮助提示
      labelWidth: 100, // 标签宽度
    },
    key: "",
    rules: [{
      required: false,
      message: "必填项"
    }]
  },

5.使用效果

image.png