封装一个金额输入框组件

6,564 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。

TIP 👉 读书不觉已春深,一寸光阴一寸金。-----王贞白《白鹿洞二首·其一》

前言

在我们日常项目开发中,我们经常会遇到一些输入框的操作,比如我们经常跟money打交道,所以封装了这款金额输入框的组件。

金额输入框组件

  • 数值为128000时,显示为 128,000.00

属性

1. value 金额数值
  • 值为数值类型
2. decimal 小数部分位数
  • 值为数值类型

  • 默认值:2

3. canRound 是否允许四舍五入
  • 值为布尔类型

  • 默认值: false

由于JS的 tofixed 方法的四舍五入存在精度问题,不建议设为true

4. canNegative 是否允许输入负数
  • 值为布尔类型

  • 默认值: true

5. suffixText 输入框后缀显示的文字
  • 值为字符串

  • 默认值:""

6. icon 输入框后缀显示的图标 (suffixText 为空时有效)
  • 值为布尔值或字符串(通过字符串则指定图标的名称)

  • 默认值:"rmb"

7. disabled 是否不可用
  • 值为布尔类型
8. readonly 是否只读
  • 值为布尔类型

事件

1. change 值改变事件
  • 参数:value 输入的数值(值为数值类型)

示例


<template>
    <MoneyInput v-model="moneyValue" @change="handleChange" ></MoneyInput>
</template>

<script>
import MoneyInput from '@/components/pc/moneyInput'

export default {
    name: 'CheckboxDemo',
    components: {
        MoneyInput
    },
    data () {
        return {
            moneyValue: 128000
        }
    },
    methods: {
        handleChange (val) {
            console.log('输入的金额为:', val)
        }
    }
}
</script>

实现MoneyInput.vue

<template>
    <div class="money-input-wrap" :class="{'show-icon': icon}">
        <template v-if="readonly">
            <span>{{ currentValue | money(currentDecimal) }}</span>
        </template>
        <template v-else>
            <div class="money-input">
                <input ref="rawInput" class="money-raw-input"
                v-model="currentValue"
                @change="handleChange($event)"
                maxlength="15"
                :disabled="disabled"
                :data-canRound="canRound"
                :data-canNegative="canNegative">
                <div class="money-show" :class="disabled ? 'disabled-input' : ''">{{currentValue | money(currentDecimal)}}</div>
            </div>
            <div v-if="suffixText || icon" class="money-suffix-wrap">
                <span v-if="suffixText" class="money-suffix-text">{{suffixText}}</span>
                <Icon v-else class="money-icon" :name="iconName"></Icon>
            </div>
        </template>
    </div>
</template>

<script>
export default {
name: 'MoneyInput',
props: {
    // 当前值
    value: Number,
    // 小数部分位数
    decimal: {
        type: Number,
        default: 2
    },
    // 是否四舍五入
    canRound: {
        type: Boolean,
        default: false
    },
    // 是否允许负数
    canNegative: {
        type: Boolean,
        default: true
    },
    // 后缀文字
    suffixText: {
        type: String
    },

    // 是否显示图标
    icon: {
        type: [Boolean, String],
        default: 'rmb'
    },

    // 是否可用
    disabled: {
        type: Boolean,
        default: false
    },

    // 是否只读
    readonly: {
        type: Boolean,
        default: false
    }
},
data () {
    return {
        currentValue: this.value,
        currentDecimal: this.decimal
    }
},
computed: {
    iconName () {
        if (typeof this.icon === 'string') {
            return this.icon
        }
        return 'rmb'
    }
},

watch: {
    value (val) {
        this.currentValue = val
    }
},

methods: {
    handleChange (event) {
        let val = event.target.value
        let numVal = Number(val)
        if (val === '' || isNaN(numVal)) {
            this.currentValue = null
            this.$emit('input', null)
            this.$emit('change', null)
        } else {
            if (!this.canNegative && numVal < 0) { // 不允许为负数
                numVal = Math.abs(numVal)
            }
            if (!this.canRound) { // 不允许四舍五入
                let numArray = numVal.toString().split('.')
                let intStr = numArray[0] // 整数部分字符串

                let decimalStr = numArray.length >= 2 ? numArray[1] : 1 // 小数部分字符串
                if (decimalStr.length > this.decimal) {
                    let newValueStr = intStr + '.' + decimalStr.substr(0, this.decimal)
                    numVal = Number(newValueStr)
                }
                } else {
                    numVal = this.fixDecimal(numVal, this.decimal) // 修正小数点位数
                }
                this.currentValue = numVal
                this.$emit('input', numVal)
                this.$emit('change', numVal)
            }
        },
        // 修正小数点位数
        fixDecimal (num, decimal) {
            let number = parseFloat(num)
            if (num !== undefined && num !== null && num !== '' && !isNaN(number)) {
                return parseFloat(number.toFixed(decimal))
            }
            return num
        }
    }
}

</script>

<style lang="scss" scoped px2rem="false">
    $icon-width: 24px;
    .money-input-wrap {
        display: table;
        width: 100%;
        height: $form-item-height;
        .money-input {
        display: table-cell;
        position: relative;
        width: 100%;
        .money-raw-input {
            position: absolute;
            top: 0;
            width: 100%;
            border: 1px solid $border-color-base;
            vertical-align: middle;
            border-radius: 4px;
            font-size: 14px;
            color: $input-font-color;
            opacity: 0;
            z-index: 1;
            &:disabled {
                background-color: $input-disabled-bg-color;
                cursor: not-allowed;
            }
            &:focus {
            @include primary-border-color();
            opacity: 1;
                &+input.money-show {
                    opacity: 0;
                }
            }
        }
        .money-show {
            position: absolute;
            top: 0;
            width: 100%;
            height: $form-item-height;
            line-height: $form-item-height - 2px;
            vertical-align: middle;
            padding: 0 5px;
            overflow: hidden;
            color: $color-text-regular;
            background-color: #FFF;
            border: 1px solid $border-color-base;
            border-radius: 4px;
            &.disabled-input {
                background-color: $input-disabled-bg-color;
                cursor: not-allowed;
            }
        }
    }
    .money-suffix-wrap {
        display: table-cell;
        min-width: 24px;
        padding: 0 5px;
        height: $form-item-height;
        vertical-align: middle;
        text-align: center;
        color: $color-text-placeholder;
        background-color: $bg-color-base;
        border: solid 1px $border-color-base;
        border-left: 0;
        border-radius: 0 4px 4px 0;
        .money-suffix-text {
            word-break: keep-all;
            white-space:nowrap;
        }
    }
    &.show-icon {
        .money-raw-input, .money-show {
            padding-right: 0;
            border-radius: 4px 0 0 4px;
        }
    }
}
</style>

index.js

/**
* 金额输入框
* @author qinglianshizhe
* @date 2021/10/11
*/
import MoneyInput from './MoneyInput.vue'
export default MoneyInput

感谢评论区大佬的点拨。

希望看完的朋友可以给个赞,鼓励一下