基于 element ui 扩展 金额输入组件

1,488 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情

element-ui 的form 表单组件

背景: 基于element ui开发后台管理,部分输入内容涉及金额输入,用户看到的单位是元,后端接口接收的单位是分,存在一个转化问题

方法一: 

特点:element-ui自带组件,需要对结果进行装换,用的地方多,感觉比较麻烦,查询结果显示的时候,需要除以100,给接口的时候需要乘以100

直接使用 inputNumver 计数器  

1.png

<template>
    <div>
        <el-form v-model="form">
            <el-form-item label="商品名称" prop="name">
                <el-input placeholder="请输入商品名称" v-model="form.name" />
            </el-form-item>
            <el-form-item label="价格" prop="price">
                <price-input :form="form" prop="price"></price-input>
            </el-form-item>
        </el-form>
    </div>
</template>
<script>
export default {
    data() {
        return {
            form: {
                name: "",
                price: 0,
            },
        };
    },
};
</script>

接口接收的时候,参数需要进行元转化为分处理:

  1. 直接乘以100,可能会有多为小数的问题。

    解决方法:

Vue.prototype.yuanToFen = function (num) {

 return parseFloat(Math.round(num * Math.pow(10, 2)) / 1);

}

方法二:

      封装组件,希望达到的效果,接收的单位是分,展示的单位元,更改的时候联动:更改元,对应的form数据里分也跟着变动。

组件PriceInput,接收参数 form:当前表单数据,prop: 对应的参数名称。

  <price-input :form="form" prop="price"></price-input>
复制代码
  •  金额需要支持边界,使用el-input
  • web 页面输入,需要限制输入的是数字,且小数点后最多两位
  • 解决方法,自定义指令,对键盘输入内容或粘贴内容进行监听,过滤数据
  • 金额转换部分逻辑(核心)
  • 接收金额为分,显示金额为元,且不改变form表单内price的单位,则显示金额需要一个新的变量用作展示:displayValue 
  • 需要在第一次接收到数据的时候,进行一次转换,赋值给displayValue
  • 监听输入框的input事件,输入框内容改变的时候,更新form.pricedisplayValue
  • 监听输入框的change事件,输入框失去焦点的时候,更新form.pricedisplayValue
  • displayValue 依赖于初次数据,和输入数据,因此使用计算属性

监听数据输入的指令代码:

Vue.directive('enterMoney', {
  inserted: function (el) {
    el.addEventListener('keypress', function (e) {
      e = e || window.event
      const charcode = typeof e.charcode === 'number' ? e.charcode : e.keyCode
      const re = /\d/
      if (charcode === 46) {
        if (el.children[0].value.includes('.')) {
          e.preventDefault()
        }
        return
      } else if (!re.test(String.fromCharCode(charcode)) && charcode && !e.ctrlKey) {
        if (e.preventDefault) {
          e.preventDefault()
        } else {
          e.returnValue = false
        }
      }
      else {
        // console.log('dir--',el.children[0].value, e.key)
        let reg = /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/
        if (el.children[0].value) {
          if (!reg.test(el.children[0].value + e.key)) {
            e.preventDefault()
          }
        }
      }
    })
  }
});

PriceInput.vue 组件:

<template>
  <div>
    <el-input
      v-enter-money
      :value="displayValue"
      :placeholder="placeholder"
      :disabled="disabled"
      @input="handleInput"
      @change="handleInputChange"
    >
    </el-input>
  </div>
</template>
<script>
export default {
  name: "PriceInput",
  props: {
    /* 初始价格 */
    form: {
      type: Object,
      default: function () {
        return {};
      },
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    prop: {
      type: String,
      default: "",
    },
    placeholder: {
      type: String,
      default: "",
    },
  },
  data() {
    return {
      currentValue: 0,
      userInput: null,
    };
  },
  watch: {
    form: {
      handler(val) {
        if (val) {
          let num = this.form[this.prop];
          if (num != undefined && num != null) {
            this.userInput = num / 100;
            this.currentValue = this.userInput;
          } else {
            this.userInput = null;
            this.currentValue = null;
            this.$set(this.form, this.prop, null);
          }
        }
      },
      immediate: true,
      // deep:true
    },
  },
  computed: {
    displayValue() {
      if (this.userInput !== null) {
        this.changeValue(this.userInput);
        return this.userInput;
      }
      let currentValue = this.currentValue;
      this.changeValue(currentValue);
      return currentValue;
    },
  },
  methods: {
    changeValue(val) {
      if (val != null && val != "") {
        this.form[this.prop] = parseFloat(
          Math.round(val * Math.pow(10, 2)) / 1
        );
      } else {
        this.form[this.prop] = null;
      }
    },
    handleInput(value) {
      this.userInput = value;
    },
    handleInputChange(value) {
      const newVal = Number(value);
      if (!isNaN(newVal) && value != "") {
        this.currentValue = parseFloat(
          Math.round(newVal * Math.pow(10, 2)) / Math.pow(10, 2)
        );
      } else {
        this.currentValue = null;
      }
      this.userInput = null;
    },
  },
};
</script>