组件封装--CurrencyInput货币数字输入框组件

图例: 

 输入除了数字以外的字符会自动过滤

组件代码:

<template>
  <div>
    <div :class="['el-input' ,'el-input--mini',{'is-disabled': inputDisabled}]">
      <input 
          ref="input"
          class="el-input__inner" 
          :disabled="inputDisabled"                             
          :value="formatValue" 
          maxlength="15" 
          @change="handleChange" 
          @input="updatevalue($event.target.value)"
          @blur="onBlur" 
          @focus="selectAll">
    </div>
  </div>
</template>

class 属性使用了数组语法和对象语法的结合,其中包含了三个类名:el-input、el-input--mini 和 is-disabled。el-input 和 el-input--mini 是组件自身的样式类名,is-disabled 是根据组件状态动态添加的类名,表示输入框是否被禁用。

ref 属性为 input,表示该元素在组件实例中的引用名称。

class 属性为 el-input__inner,表示输入框内部的样式。

:disabled 属性绑定了组件实例的 inputDisabled 属性,用于动态设置输入框是否禁用。

:value 属性绑定了组件实例的 formatValue 属性,用于动态设置输入框中的值。

maxlength 属性为 15,表示输入框中最多可以输入 15 个字符。

@change 属性绑定了组件实例的 handleChange 方法,表示输入框的值发生改变时需要执行的回调函数。

@input 属性绑定了组件实例的 updateValue 方法,表示输入框的值发生改变时需要更新组件实例的 value 属性。

@blur 属性绑定了组件实例的 onBlur 方法,表示输入框失去焦点时需要执行的回调函数。

@focus 属性绑定了组件实例的 selectAll 方法,表示输入框获得焦点时需要执行的回调函数,用于选中输入框中的所有文本。
 <script>
    import accounting from '..................'
    export default {
      name: 'CurrencyInput',
      inject: {
        elForm: {
          default: ''
        },
        elFormItem: {
          default: ''
        }
      },
      props: {
        value: {
          type: [String, Number],
          default: 0,
          desc: '数值'
        },
        symbol: {
          type: String,
          default: '',
          desc: '货币标识符'
        },
        decimal: {
          type: Number,
          default: 0,
          desc: '小数位'
        },
        /* eslint-disable */
        disabled: [Boolean, undefined],
        elvalue: [String, Number]
      },
      data() {
        return {
          focused: false
        }
      },
      computed: {
        inputDisabled() {
          return this.disabled || (this.elForm || {}).disabled;
        },
        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)
            }
          }
        }
      },
      methods: {
        handleChange(){
          this.$emit('change', this.formatValue)
          this.dispatch('ElFormItem', 'el.form.change', [this.value]);
        },
        updatevalue(value) {
          if(this.decimal && value.indexOf('.')>-1 &&         
     value.substring(value.lastIndexOf('.')+1).length>this.decimal ) return
          var formatvalue = value ? accounting.unformat(value) : ''
          this.$emit('input', formatvalue)
        },
        onBlur() {
          this.focused = false
          this.$emit('blur', event)
          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>

使用方法:

引入组件:

import CurrencyInput from '................'

<details>
  <summary>【CurrencyInput货币数字输入框组件】</summary>

    - 示例程序:
    ```
    <el-form-item label="" prop="">
      <CurrencyInput
        v-model=""
        field-type="currency"
        name="currency"
        symbol="¥"
        :decimal="2"
        label="测试金额"
        placeholder="请输入"
        clearable
      />
    ```
  - 属性说明:
    `field-type`固定为`currency`;`symbol`表示要显示的货币符号,可空;`decimal`表示要显示的小数位数。
</details>

引入的文件 accounting.min.js 它是一个第三方库,用于进行数字和货币格式化。

/* eslint-disable */
/*!
 * accounting.js v0.4.2, copyright 2014 Open Exchange Rates, MIT license, http://openexchangerates.github.io/accounting.js
 */
(function(p, z) { function q(a) { return !!(a === '' || a && a.charCodeAt && a.substr) } function m(a) { return u ? u(a) : v.call(a) === '[object Array]' } function r(a) { return v.call(a) === '[object Object]' } function s(a, b) { var d; var a = a || {}; var b = b || {}; for (d in b)b.hasOwnProperty(d) && a[d] == null && (a[d] = b[d]); return a } function j(a, b, d) { var c = []; var e; var h; if (!a) return c; if (w && a.map === w) return a.map(b, d); for (e = 0, h = a.length; e < h; e++)c[e] = b.call(d, a[e], e, a); return c } function n(a, b) { a = Math.round(Math.abs(a)); return isNaN(a) ? b : a } function x(a) { var b = c.settings.currency.format; typeof a === 'function' && (a = a()); return q(a) && a.match('%v') ? { pos: a, neg: a.replace('-', '').replace('%v', '-%v'), zero: a } : !a || !a.pos || !a.pos.match('%v') ? !q(b) ? b : c.settings.currency.format = { pos: b, neg: b.replace('%v', '-%v'), zero: b } : a } var c = { version: '0.4.1', settings: { currency: { symbol: '$', format: '%s%v', decimal: '.', thousand: ',', precision: 2, grouping: 3 }, number: { precision: 0, grouping: 3, thousand: ',', decimal: '.' }}}; var w = Array.prototype.map; var u = Array.isArray; var v = Object.prototype.toString; var o = c.unformat = c.parse = function(a, b) { if (m(a)) return j(a, function(a) { return o(a, b) }); a = a || 0; if (typeof a === 'number') return a; var b = b || '.'; var c = RegExp('[^0-9-' + b + ']', ['g']); var c = parseFloat(('' + a).replace(/\((.*)\)/, '-$1').replace(c, '').replace(b, '.')); return !isNaN(c) ? c : 0 }; var y = c.toFixed = function(a, b) { var b = n(b, c.settings.number.precision); var d = Math.pow(10, b); return (Math.round(c.unformat(a) * d) / d).toFixed(b) }; var t = c.formatNumber = c.format = function(a, b, d, i) { if (m(a)) return j(a, function(a) { return t(a, b, d, i) }); var a = o(a); var e = s(r(b) ? b : { precision: b, thousand: d, decimal: i }, c.settings.number); var h = n(e.precision); var f = a < 0 ? '-' : ''; var g = parseInt(y(Math.abs(a || 0), h), 10) + ''; var l = g.length > 3 ? g.length % 3 : 0; return f + (l ? g.substr(0, l) + e.thousand : '') + g.substr(l).replace(/(\d{3})(?=\d)/g, '$1' + e.thousand) + (h ? e.decimal + y(Math.abs(a), h).split('.')[1] : '') }; var A = c.formatMoney = function(a, b, d, i, e, h) { if (m(a)) return j(a, function(a) { return A(a, b, d, i, e, h) }); var a = o(a); var f = s(r(b) ? b : { symbol: b, precision: d, thousand: i, decimal: e, format: h }, c.settings.currency); var g = x(f.format); return (a > 0 ? g.pos : a < 0 ? g.neg : g.zero).replace('%s', f.symbol).replace('%v', t(Math.abs(a), n(f.precision), f.thousand, f.decimal)) }; c.formatColumn = function(a, b, d, i, e, h) { if (!a) return []; var f = s(r(b) ? b : { symbol: b, precision: d, thousand: i, decimal: e, format: h }, c.settings.currency); var g = x(f.format); var l = g.pos.indexOf('%s') < g.pos.indexOf('%v') ? !0 : !1; var k = 0; var a = j(a, function(a) { if (m(a)) return c.formatColumn(a, f); a = o(a); a = (a > 0 ? g.pos : a < 0 ? g.neg : g.zero).replace('%s', f.symbol).replace('%v', t(Math.abs(a), n(f.precision), f.thousand, f.decimal)); if (a.length > k)k = a.length; return a }); return j(a, function(a) { return q(a) && a.length < k ? l ? a.replace(f.symbol, f.symbol + Array(k - a.length + 1).join(' ')) : Array(k - a.length + 1).join(' ') + a : a }) }; if (typeof exports !== 'undefined') { if (typeof module !== 'undefined' && module.exports)exports = module.exports = c; exports.accounting = c } else typeof define === 'function' && define.amd ? define([], function() { return c }) : (c.noConflict = (function(a) { return function() { p.accounting = a; c.noConflict = z; return c } }(p.accounting)), p.accounting = c) })(this)

------------------------------------------------------------------------------------------------------------------------------

js中的方法解释:

        computed:{} 中,

        名为 inputDisabled 对象方法,它返回一个布尔值。该方法的作用是判断当前输入框是否被禁用,或者其所属的表单是否被禁用。

具体来说,方法通过检查两个属性来判断输入框是否被禁用:

  • this.disabled:表示输入框本身是否被禁用。如果该属性为 true,则表示输入框被禁用。
  • (this.elForm || {}).disabled:表示输入框所属的表单是否被禁用。该属性使用了 JavaScript 中的短路操作符 || 和空对象 {}。如果输入框没有所属的表单,则 this.elForm 为 undefined,短路操作符会返回空对象 {},从而避免了访问 undefined 对象的错误。如果表单被禁用,则该属性为 true

因此,当输入框被禁用或其所属的表单被禁用时,该方法返回 true,否则返回 false

        名为 formatValue 对象方法,它返回一个格式化后的字符串。

        该方法用于将输入框的值进行格式化。具体来说,当输入框处于焦点状态时,该方法会将输入框的值进行反格式化,即将货币符号、千位分隔符和小数位进行去除。当输入框失去焦点时,该方法会将输入框的值进行格式化,即添加货币符号、千位分隔符和小数位。

具体实现逻辑如下:

  • 当输入框处于焦点状态时,if (this.focused) 为真,方法会判断输入框的值是否为空。如果不为空,则使用 accounting.unformat 方法进行反格式化,将输入框的值转换为数字类型。否则,返回空字符串(即 '')。
  • 当输入框失去焦点时,if (this.focused) 为假,方法会判断输入框的值是否为数字 0。如果是,则使用 accounting.formatMoney 方法进行格式化,添加货币符号、千位分隔符和小数位。如果输入框的值为空字符串、null 或 undefined,则返回空字符串。否则,也使用 accounting.formatMoney 方法进行格式化。

在这段代码中,accounting 在上方已注明.

methods: {} 中,

        名为 handleChange 一个对象方法,它没有返回值。

        该方法主要用于处理输入框的变化事件,并触发相关的事件和钩子函数。具体来说,该方法会执行以下两个操作:

  1. 使用 $emit 方法触发 change 事件,并将格式化后的值作为参数传递给事件的回调函数。这里的 formatValue 是上面的一个计算属性,用于根据输入框的状态和数值进行格式化处理,返回格式化后的货币字符串或空字符串。
  2. 使用 dispatch(此方法在文章最下方) 方法触发 el.form.change 钩子函数,并将输入框的值作为参数传递给该函数。

需要注意的是,该方法依赖一些对象属性来进行处理,包括:

  • $emit 方法:用于触发 Vue 实例上的自定义事件。
  • this.formatValue 属性:表示输入框的格式化后的值。
  • this.value 属性:表示输入框的原始值。
  • dispatch 方法:用于在组件树中向上派发事件。

因此,在使用该方法前,需要确保对象的这些属性和方法已经被正确设置。

        名为 updatevalue 对象方法,没有返回值。

        该方法主要用于更新输入框的值,并触发相关的事件。具体来说,该方法会执行以下两个操作:

  1. 如果输入框的小数位数(即 this.decimal 属性)大于 0,且输入的值包含小数点,并且小数部分的位数大于小数位数,则直接返回,不进行任何操作。
  2. 使用 accounting.unformat 方法将输入框的值进行反格式化,即将货币符号、千位分隔符和小数位进行去除,并将结果赋值给变量 formatvalue。如果输入框的值为空,则将 formatvalue 设置为空字符串。
  3. 使用 $emit 方法触发 input 事件,并将 formatvalue 作为参数传递给事件的回调函数。这里的 input 事件是一个 Vue 内置的事件,用于响应用户输入操作。

需要注意的是,该方法依赖一些对象属性和方法来进行处理,包括:

  • this.decimal 属性:表示货币小数位数。
  • value 参数:表示输入框的原始值。
  • accounting.unformat 方法:用于将货币字符串进行反格式化,将其转换为数值类型。
  • $emit 方法:用于触发 Vue 实例上的自定义事件。

因此,在使用该方法前,需要确保对象的这些属性和方法已经被正确设置。

        名为 onBlur 对象方法,它没有返回值。

        该方法主要用于处理输入框失去焦点事件,并触发相关的事件和钩子函数。具体来说,该方法会执行以下三个操作:

  1. 将输入框的 focused 属性设置为 false,表示输入框失去了焦点。
  2. 使用 $emit 方法触发 blur 事件,并将 event 对象作为参数传递给事件的回调函数。这里的 event 对象是一个 JavaScript 事件对象,表示输入框失去焦点事件的相关信息。
  3. 使用 dispatch 方法(此方法在文章最下方)触发 el.form.blur 钩子函数,并将输入框的值作为参数传递给该函数。

需要注意的是,该方法依赖一些对象属性和方法来进行处理,包括:

  • this.focused 属性:表示输入框是否处于焦点状态。
  • $emit 方法:用于触发 Vue 实例上的自定义事件。
  • event 参数:表示输入框失去焦点事件的相关信息。
  • dispatch 方法:用于在组件树中向上派发事件。

因此,在使用该方法前,需要确保对象的这些属性和方法已经被正确设置

        名为 selectAll 对象方法,它没有返回值。

        该方法主要用于选中输入框中的所有文本,并将输入框设置为焦点状态。具体来说,该方法会执行以下两个操作:

  1. 将输入框的 focused 属性设置为 true,表示输入框处于焦点状态。
  2. 使用 setTimeout 方法来延时执行一个回调函数,该回调函数会在下一个事件循环中被执行。在回调函数中,使用 select 方法选中输入框中的所有文本。这里的 event.target 表示触发事件的元素,即输入框元素。

需要注意的是,由于 select 方法必须在输入框处于焦点状态下才能生效,因此在执行该方法前,需要确保输入框已经处于焦点状态,即通过设置 this.focused 属性为 true 来实现。此外,为了确保 select 方法能够正常工作,需要在下一个事件循环中执行该方法,即使用 setTimeout 方法来进行延时处理。

        名为 dispatch 对象方法,用于在组件树中向上派发事件,并触发指定的钩子函数。它没有返回值。

        该方法接受三个参数:componentName 表示需要触发钩子函数的组件名称;eventName 表示需要触发的钩子函数名称;params 表示需要传递给钩子函数的参数列表。

        该方法会从当前组件开始向上遍历组件树,直到找到指定名称的组件或遍历到根组件为止。在遍历过程中,使用 parent 变量来表示当前遍历到的组件,使用 name 变量来表示当前组件的名称。如果当前组件的名称与指定名称不一致,则继续向上遍历其父组件,直到找到指定名称的组件或遍历到根组件为止。

        如果找到了指定名称的组件,即 parent 不为 null,则通过 parent.$emit 方法触发该组件上的指定钩子函数,并将参数列表传递给该函数。这里的 apply 方法用于将参数列表展开成一个个参数,以便传递给 $emit 方法。

        需要注意的是,该方法依赖于 $parent 和 $root 属性,这两个属性分别表示当前组件的父组件和根组件。由于 $parent 和 $root 属性可能为 null,因此在使用该方法前需要进行判断,以确保这两个属性存在。此外,该方法还依赖于 $options.componentName 属性,该属性为组件的名称,需要在组件定义时进行设置。

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值