基于el-input包装的金额输入框,展示时千分位分割,输入时是数字。

<template>
  <el-tooltip :content="value" :disabled="tooltipDisabled || !showTooltip" :effect="effect" :placement="placement">
    <el-input
      v-bind="$attrs"
      :class="customClass"
      v-model="value"
      oninput="value=value.replace(/^([0-9-]\d*\.?\d{0,2})?.*$/,'$1')"
      ref="inputRef"
      :disabled="disabled"
      :value="isfocus ? value : formatMoney(value, 2)"
      @mouseenter="judgeMouseEnter"
      @mouseleave="judgeMouseLeave"
      @change="changeContent($event)"
      @focus="isfocus = true"
      @blur="isfocus = false"
    >
      <template #prepend v-if="$slots.prepend">
        <slot name="prepend"></slot>
      </template>
      <template #append v-if="$slots.append">
        <slot name="append"></slot>
      </template>
    </el-input>
  </el-tooltip>
</template>

<script lang="ts">
import { computed, defineComponent, reactive, toRefs, watch } from 'vue';

export default defineComponent({
  name: 'FmisMoneyInput',
  props: {
    modelValue: {
      type: [String, Number],
      default: '',
    },
    effect: {
      type: String,
      default: 'dark',
    },
    placement: {
      type: String,
      default: 'top',
    },
    tooltipDisabled: {
      type: Boolean,
      default: !true,
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    customClass: {
      type: String,
      default: '',
    },
    // 是否可以输入负数 默认可以 不可以传false
    isComplex: {
      type: Boolean,
      default: true,
    },
  },
  setup(props, context) {
    let padding = 0;
    const state = reactive({
      input: <any>null,
      fakeEle: <any>null,
      showTooltip: false,
      value: props.modelValue,
      isfocus: false,
    });
    const refs = reactive({
      inputRef: <any>null,
    });
    // 四舍五入
    const round = (num: any, scale?: number) => {
      if (num == null) {
        return 0;
      }
      if (scale == null) {
        scale = 0;
      }
      const pow = Math.pow(10, scale);
      return Math.round((num * (pow * 10)) / 10) / pow;
    };
    // 格式化金额
    const formatMoney = (val: any, precision: any, prefix?: string, suffix?: string) => {
      if (val === null || val === '' || val === undefined) {
        return val;
      }
      if (prefix == null) {
        prefix = '';
      }
      if (suffix == null) {
        suffix = '';
      }
      let value = '';
      if (precision === null || precision === '') {
        value = val + '';
      } else {
        value = parseFloat(val).toFixed(precision) + '';
      }
      const groupSeparator = ','; // 分隔符
      const decimalSeparator = '.'; // 分隔小数和整数部门
      let s1 = value;
      let s2 = '';
      const dpos = value.indexOf('.');
      if (dpos >= 0) {
        s1 = value.substring(0, dpos);
        s2 = value.substring(dpos + 1, value.length);
      }
      if (groupSeparator) {
        const p = /(\d+)(\d{3})/;
        while (p.test(s1)) {
          s1 = s1.replace(p, '$1' + groupSeparator + '$2');
        }
      }
      if (s2) {
        return prefix + s1 + decimalSeparator + s2 + suffix;
      } else {
        return prefix + s1 + suffix;
      }
    };
    const judgeMouseEnter = () => {
      // console.log('鼠标移入');
      state.input = findInnerInput(Array.from(refs.inputRef.$el.children));
      // 未匹配到内部input元素
      if (!state.input) return;

      padding = getInputPaddingCount();
      const styles = window.getComputedStyle(state.input);
      state.fakeEle = document.createElement('div');
      // 将输入框元素的 font 属性赋给辅助的 div 元素
      state.fakeEle.style.font = styles.font;
      state.fakeEle.style.cssText = 'position:absolute;left:-9999px;visibility:hidden;white-space:nowrap;';
      document.body.appendChild(state.fakeEle);
      showTooltipChange(props.modelValue);
    };
    const judgeMouseLeave = () => {
      // console.log('鼠标移出');
      // 移除临时节点
      if (state.fakeEle?.parentNode) {
        document.body.removeChild(state.fakeEle);
      }
    };
    const showTooltipChange = (val: any) => {
      if (val === '' || !state.fakeEle || !state.input) {
        state.showTooltip = false;
        return;
      }
      state.fakeEle.innerHTML = val;
      state.showTooltip = state.fakeEle.offsetWidth > state.input.offsetWidth - padding;
    };
    // 查找input文本元素
    const findInnerInput = (nodes: any[]) => {
      let findNode = null;
      nodes.forEach((node) => {
        if (node.className === 'el-input__inner') {
          findNode = node;
        } else if (node.className === 'el-input__wrapper') {
          Object.values(node.children).forEach((childNode: any) => {
            if (childNode.className === 'el-input__inner') {
              findNode = childNode;
            }
          });
        }
      });
      return findNode;
    };
    // 获取input内容元素padding边距
    const getInputPaddingCount = () => {
      const styles = window.getComputedStyle(state.input);
      return parseInt(styles.paddingLeft) + parseInt(styles.paddingRight);
    };
    watch(
      () => props.modelValue,
      (value) => {
        showTooltipChange(value);
      }
    );
    // change事件解决有时候 输过值 但是显示无的问题
    const changeContent = (val: any) => {
      state.isfocus = false;
      // 输入小数点后位数太多 默认保留两位小数(四舍五入)
      state.value = round(val, 2);
      // 1 判断能否输入负数
      if (props.isComplex == false && val.startsWith('-')) {
        // console.log('不能输入负数');
        state.value = Number(val.slice(1));
      }
      context.emit('onChange', state.value);
      context.emit('update:modelValue', state.value);
    };
   watch(
      ()=> props.modelValue,
      (val)=>{
        state.value = val;
      }
    )
    return {
      ...toRefs(state),
      ...toRefs(refs),
      judgeMouseEnter,
      judgeMouseLeave,
      changeContent,
      formatMoney,
    };
  },
});
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值