vue中使用自定义金额格式化组件,对金额进行千分位格式化

分两种情况:不使用vue/cli脚手架搭建和使用vue/cli脚手架搭建的项目

一、不使用vue/cli脚手架搭建

1、该组件基于vue,element,accountingjs

2、引入相应的js文件

<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
<script src="https://cdn.bootcss.com/accounting.js/0.4.1/accounting.js"></script>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>

3、如何使用:html部分

<div id="app">
    <div style="display:inline-block">
        <currency-input v-model="price" :decimal="4" style="width:200px;" @blur="inputBlur"></currency-input>
        <el-button type="primary" size="small" @click="submit">提交</el-button>
    </div>
</div>

4、如何使用:js部分

Vue.component('currency-input', {
  template: '\
                <div class="el-input el-input--small" v-bind:class="{\'is-disabled\':disabled}">\
                    <input\
                        ref="input"\
                        v-bind:value="formatValue"\
                        v-on:input="onInput($event.target.value)"\
                        v-on:focus="selectAll"\
                        v-on:blur="onBlur"\
                        v-bind:disabled="disabled"\
                        class="el-input__inner"\
                    >\
                </div>\
            ',
  props: {
    value: {
      type: [String, Number],
      default: 0,
      desc: '数值'
    },
    symbol: {
      type: String,
      default: "",
      desc: '货币标识符'
    },
    decimal: {
      type: Number,
      default: 2,
      desc: '小数位'
    },
    disabled: {
      type: Boolean,
      default: false,
      desc: "是否禁止"
    }
  },
  data() {
    return {
      focused: false
    };
  },
  computed: {
    formatValue() {
      if (this.focused) {
        return this.$accounting.unformat(this.value);
      } else {
        return this.$accounting.formatMoney(this.value, this.symbol, this.decimal);
      }
    }
  },
  watch: {
    value(val) {if (this.validateEvent) {
        this.dispatch('ElFormItem', 'el.form.change', [val]);
      }
    },
  },
  methods: {
    onInput(value) {
      var formatvalue = this.$accounting.unformat(value);
      this.$emit("input", formatvalue);
    },
    onBlur() {
      this.focused = false;
      this.$emit("blur");
      this.dispatch("ElFormItem", "el.form.blur", [this.value]);
    },
    selectAll(event) {
      this.focused = true;
      setTimeout(function () {
        event.target.select()
      }, 0)
    },
    dispatch(componentName, eventName, params) {
      var parent = this.$parent || this.$root;
      var name = parent.$options.componentName;
      while (parent && (!name || name !== componentName)) {
        parent = parent.$parent;
        if (parent) {
          name = parent.$options.componentName;
        }
      }
      if (parent) {
        parent.$emit.apply(parent, [eventName].concat(params));
      }
    }
  }
});

二、使用vue/cli脚手架搭建

currencyInput/CurrencyInput.vue

<template>
  <div>
    <div class="el-input el-input--small" v-bind:class="{'is-disabled':disabled}">
      <input class="el-input__inner" v-bind:value="formatValue" v-on:input="updatevalue($event.target.value)" v-on:blur="onBlur" v-on:focus="selectAll" v-bind:disabled="disabled" />
    </div>
  </div>
</template>

<script>
import accounting from "accounting";
export default {
  props: {
    value: {
      type: [String, Number],
      default: 0,
      desc: "数值",
    },
    symbol: {
      type: String,
      default: "",
      desc: "货币标识符",
    },
    decimal: {
      type: Number,
      default: 2,
      desc: "小数位",
    },
    disabled: {
      type: Boolean,
      default: false,
      desc: "是否禁止",
    },
  },
  data() {
    return {
      focused: false,
    };
  },
  computed: {
    formatValue() {
      if (this.focused) {
        return this.value ? accounting.unformat(this.value) : "";
      } else {
        if (this.value === 0) {
          return accounting.formatMoney(this.value, this.symbol, this.decimal);
        } else if (
          this.value === "" ||
          this.value === null ||
          this.value === undefined
        ) {
          return "";
        } else {
          return accounting.formatMoney(this.value, this.symbol, this.decimal);
        }
      }
    },
  },
  watch: {
    value(val) {if (this.validateEvent) {
        this.dispatch("ElFormItem", "el.form.change", [val]);
      }
    },
  },
  methods: {
    updatevalue(value) {
      var formatvalue = !!value ? accounting.unformat(value) : "";
      this.$emit("input", formatvalue);
    },
    onBlur() {
      this.focused = false;
      this.$emit("blur");
      this.dispatch("ElFormItem", "el.form.blur", [this.value]);
    },
    selectAll(event) {
      this.focused = true;
      setTimeout(() => {
        event.target.select();
      }, 0);
    },

    dispatch(componentName, eventName, params) {
      var parent = this.$parent || this.$root;
      var name = parent.$options.componentName;

      while (parent && (!name || name !== componentName)) {
        parent = parent.$parent;

        if (parent) {
          name = parent.$options.componentName;
        }
      }
      if (parent) {
        parent.$emit.apply(parent, [eventName].concat(params));
      }
    },
  },
};
</script>

currencyInput/index.js

import currencyInputComponent from "./CurrencyInput";

const currencyInput = {
    install:function(Vue){
        Vue.component("currency-input",currencyInputComponent)
    }
}

export default currencyInput

main.js

// 自定义金额格式化组件,并全局注册
import currencyInput from "./components/CurrencyInput";
Vue.use(currencyInput)

import accounting from 'accounting'

使用方法

<currency-input v-model="bhform.regCaptial"></currency-input>

三、封装成公共组件:

<template>
    <el-input
      v-model="displayValue"
      @blur="handleBlur"
      @focus="handleFocus"
      :placeholder="placeholder">
    </el-input>
  </template>
  
  <script>
  export default {
    name: 'FormattedInput',
    props: {
      value: {
        type: [String, Number],
        default: '',
      },
      placeholder: {
        type: String,
        default: '请输入金额',
      },
    },
    data() {
      return {
        // 内部存储的格式化显示值
        displayValue: '',
      };
    },
    watch: {
      // 监听父组件传递的 value 变化,更新显示值
      value(newVal) {
        console.log(newVal);
        
        this.updateDisplayValue(newVal);
      },
    },
    mounted() {
      // 初始化时根据父组件传递的 value 更新显示值
      this.updateDisplayValue(this.value);
    },
    methods: {
      // 更新显示值,并确保显示值为格式化后的金额
      updateDisplayValue(value) {
        if (value === '' || value === null || value === undefined) {
          this.displayValue = '';
          return;
        }
        // 将值转换为数字
        const num = parseFloat(value);
        if (!isNaN(num)) {
          // 保留两位小数并添加千分位逗号
          this.displayValue = num.toLocaleString('en-US', {
            minimumFractionDigits: 2,
            maximumFractionDigits: 2,
          });
        } else {
          this.displayValue = '';
        }
      },
      // 失去焦点时格式化金额
      handleBlur() {
        // 移除所有非数字字符(除了小数点)
        let value = this.displayValue.replace(/[^0-9.]/g, '');
        
        // 确保只有一个小数点
        const parts = value.split('.');
        if (parts.length > 2) {
          value = parts[0] + '.' + parts.slice(1).join('');
        }
  
        // 转换为数字
        const num = parseFloat(value);
        if (!isNaN(num)) {
          // 保留两位小数
          const fixedNum = Math.round(num * 100) / 100;
          // 更新显示值为格式化后的金额
          this.displayValue = fixedNum.toLocaleString('en-US', {
            minimumFractionDigits: 2,
            maximumFractionDigits: 2,
          });
          // 触发 input 事件,通知父组件值变化,传递纯净值
          this.$emit('input', fixedNum.toString());
        } else {
          // 如果输入无效,清空显示值
          this.displayValue = '';
          this.$emit('input', '');
        }
      },
      // 获得焦点时移除格式化,方便编辑
      handleFocus() {
        // 如果有千分位逗号,移除后便于编辑
        if (this.displayValue.includes(',')) {
          this.displayValue = this.displayValue.replace(/,/g, '');
        }
      },
    },
  };
  </script>
  
  <style scoped>
  /* 样式可根据需要自定义 */
  </style>

自定义组件的使用,在父组件中使用:

<template>
  <el-form ref="form" :model="formData" label-width="120px">
    <el-form-item label="金额" prop="amount" :rules="[{ required: true, message: '请输入金额', trigger: 'blur' }]">
      <formatted-input
        v-model="formData.amount"
        placeholder="请输入金额">
      </formatted-input>
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="submitForm">提交{{ formData.amount }}</el-button>
    </el-form-item>
  </el-form>
</template>

<script>
import FormattedInput from './FormattedInput.vue';

export default {
  components: {
    FormattedInput,
  },
  data() {
    return {
      formData: {
        amount: '12122', // 父组件接收到的是纯净的金额值
      },
    };
  },
  methods: {
    submitForm() {
      // 直接使用 formData.amount,它已经是纯净的数字字符串
      // 如果需要数值类型,可以转换为 Number
      const amount = parseFloat(this.formData.amount);
      
      this.$message({
        message: `提交的金额为:${amount}`,
        type: 'success',
      });
      
      // 示例:实际提交逻辑
      this.$refs.form.validate(valid => {
        if (valid) {
          // 提交 amount 到服务器
          console.log('提交的金额:', amount);
          // 例如:
          // axios.post('/api/submit', { amount: amount })
        } else {
          console.log('表单验证失败');
          return false;
        }
      });
    },
  },
};
</script>

<style scoped>
/* 样式可根据需要自定义 */
</style>

 

github地址:https://github.com/wjs0509/vue-currency-input

posted @ 2019-07-08 15:15  wjs0509  阅读(15383)  评论(0)    收藏  举报