此组件是基于element-uiel-input组件的再封装,主要用来在输入过程中,显示为数字模式,在失去焦点时加上千分符;同时保持父组件传入的值始终保持数字模式,不必要再去人工转化数据格式
先上vue文件代码:

<template>
  <el-input
    v-model="inputValue"
    v-bind="$attrs"
    :maxlength="maxlength"
    @input="handleInput"
    @focus="handleFocus"
    @blur="handleBlur"
    @change="handleChange"
  >
    <template slot="append">
      <slot name="append"></slot>
    </template>
  </el-input>
</template>

<script>
import { inputNumber } from '@/utils/inputNumber'
import { formatMoney } from '@/utils/formatMoney'

export default {
  props: {
    value: {
      type: [String, Number],
      default: ''
    },
    // 金额位数格式(a-b);a:整数位数;b:小数位数
    format: {
      type: String,
      default: '11-2'
    }
  },
  data () {
    return {
      inputValue: '',
      inputing: false
    }
  },
  computed: {
    integerNum () {
      return Number(this.format.split('-')[0])
    },
    decimalNum () {
      return Number(this.format.split('-')[1])
    },
    maxlength () {
      return this.integerNum + (this.decimalNum > 0 ? this.decimalNum + 1 : this.decimalNum)
    }
  },
  watch: {
    value: {
      immediate: true,
      handler (n) {
        if (!n) {
          this.inputValue = n
          return
        }
        if (this.inputing) {
          this.inputValue = n
        } else {
          this.inputValue = formatMoney(inputNumber(n.toString()), this.format)
        }
      }
    }
  },
  methods: {
    handleInput (val) {
      this.inputing = true
      let money = inputNumber(val)
      const format = this.format
      const intNum = Number(format.split('-')[0])
      const decimalNum = Number(format.split('-')[1])
      const moneyArr = money.split('.')
      moneyArr[0] = moneyArr[0].length > intNum ? moneyArr[0].substr(0, intNum) : moneyArr[0]
      if (moneyArr[1]) {
        moneyArr[1] = moneyArr[1].length > decimalNum ? moneyArr[1].substr(0, decimalNum) : moneyArr[1]
      }
      money = moneyArr.join('.')
      this.inputValue = money
      let value = ''
      if (money === '-' || money === '.') {
        value = ''
      } else if (money !== '') {
        value = Number(inputNumber(money))
      }
      this.$emit('input', value)
    },
    handleChange (val) {
      this.inputing = true
      this.$emit('change', Number(val.replaceAll(',', '')))
    },
    handleBlur (e) {
      this.inputing = false
      this.inputValue = formatMoney(inputNumber(e.target.value), this.format)
      this.$emit('blur', e)
    },
    handleFocus (e) {
      this.inputing = true
      this.inputValue = inputNumber(this.inputValue)
      this.$emit('focus', e)
    }
  }
}
</script>

上述用到的两个方法代码如下:
formatMoney:

/**
 * 格式化金额
 * @param money { String / Number } 金额
 * @param format { String } a-b:限制输入的字符长度,a:整数长度,b:小数长度
 * @returns {string|null}
 */
export const formatMoney = (money, format) => {
  if (typeof money === 'number') {
    money = money.toString()
  }
  if (money === '-' || !money) return money
  if (!format) format = '11-2'
  const intNum = Number(format.split('-')[0])
  const decimalNum = Number(format.split('-')[1])
  const moneyArr = money.split('.')
  moneyArr[0] = moneyArr[0].length > intNum ? moneyArr[0].substr(0, intNum) : moneyArr[0]
  if (moneyArr[1]) {
    moneyArr[1] = moneyArr[1].length > decimalNum ? moneyArr[1].substr(0, decimalNum) : moneyArr[1]
  }
  money = moneyArr.join('.')
  const isNegativeNum = money.startsWith('-')
  const pointPosition = money.indexOf('.')
  const decimal = pointPosition !== -1 ? money.substr(pointPosition) : ''
  const integer = Math.abs(parseInt(money).toString()).toString()
  const integerArrReverse = integer.split('').reverse().join('')
  const moneyStringify = `${isNegativeNum ? '-' : ''}${integerArrReverse.replace(/(\d{3})(?=\d)/g, '$1,').split('').reverse().join('')}${decimal}`
  return moneyStringify
}

inputNumber:

// 此方法用来实现将一个字符串通过replace方法,格式化为普通数字格式(包括正负整数、正负浮点数都支持)
export const inputNumber = val => {
  if (val === '-' || !val) return val
  if (val === '.') return ''
  // 下列代码中正则表达式的非捕获组(?<=)在IE浏览器中不支持,所以弃用
  // const reg1 = /[^\d|^\-|\^.]/g // 匹配所有非数字,非-,非.的字符
  // const reg2 = /(?<=[\.|\-])[^\d]/g // 匹配所有.和-字符后的非数字字符
  // const reg3 = /(?<=\.\d*)\./g // 匹配小数后的.
  // const reg4 = /(?<=\d)\-/g // 匹配-后面的非数字
  // return val.replace(reg1, '').replace(reg2, '').replace(reg3, '').replace(reg4, '')

  const reg1 = /[^\d|\-|\.]/g
  const reg2 = /(\d|\.)\-+/g
  const str = val.replace(reg1, '').replace(reg2, '$1')
  const pointArr = str.split('.')
  let value = ''
  if (pointArr.length > 1) {
    pointArr.forEach((item, index) => {
      value = value + item
      if (!index) {
        value = value + '.'
      }
    })
  } else {
    value = str
  }
  return value
}

inputNumber方法因博主本人正则水平有限,只能写成目前这样,期待大神有更好的实现方式

Logo

前往低代码交流专区

更多推荐