一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

以原生货币符号取代vue-currency-input

时间:2026-06-19 09:57:00 编辑:袖梨 来源:一聚教程网

代替vue-currency-input原生货币符号,

vue-currency-input,使用缺点

  1. 小数点输入光标会跳动
  2. 货币符号无法设置输入框右侧
  3. 输入内容无法展示小数点
  4. 兼容 element-plus的el-input功能差

使用环境UI组件库element-plus,直接上代码,

CurrencyInput.vue

 复制代码<template>
  <div class="currency-input">
    <label v-if="label" :for="id" class="label">{{ label }}</label>
    <div class="input-wrapper">
      <el-input :id="id" v-model="inputValue" :placeholder="placeholder" :disabled="disabled" @focus="onFocus"
        @blur="onBlur">
        <template #[slotName]>
          <span class="currency-symbol">{{ currencySymbol }}</span>
        </template>
      </el-input>
    </div>
  </div>
</template><script setup lang="ts">
import { ref, computed, watch, onMounted,  } from 'vue';// 计算属性返回插槽名
const slotName = computed(() => props.appendMode);interface Props {
  modelValue?: number | null;
  label?: string;
  placeholder?: string;
  disabled?: boolean;
  id?: string;
  currency?: string;
  locale?: string;
  decimalPlaces?: number;
  min?: number;
  max?: number;
  precision?: number; // 小数点后保留位数
  appendMode?: 'prefix' | 'suffix'; // 追加模式,前缀或后缀
}const props = withDefaults(defineProps<Props>(), {
  modelValue: null,
  label: '',
  placeholder: '',
  disabled: false,
  id: 'currency-input',
  currency: 'CNY',
  locale: 'zh-CN',
  decimalPlaces: 2,
  min: -Infinity,
  max: Infinity,
  precision: 2,
  appendMode: 'suffix', // 追加模式,默认为后缀
});const emit = defineEmits(['update:modelValue', 'focus', 'blur']);// 输入框显示值
const inputValue = ref('');// 是否聚焦
const isFocused = ref(false);// 获取货币符号
const currencySymbol = computed(() => {
  try {
    const formatter = new Intl.NumberFormat(props.locale, {
      style: 'currency',
      currency: props.currency,
      minimumFractionDigits: 0,
      maximumFractionDigits: 0
    });
    const parts = formatter.formatToParts(1);
    const symbolPart = parts.find(part => part.type === 'currency');
    return symbolPart ? symbolPart.value : props.currency;
  } catch {
    return props.currency;
  }
});// 数字转为千分位格式
const toFormatted = (num: number | null): string => {
  if (num === null || isNaN(num)) return '';
  return new Intl.NumberFormat(props.locale, {
    minimumFractionDigits: props.decimalPlaces,
    maximumFractionDigits: props.decimalPlaces
  }).format(num);
};// 字符串解析为数字
const toNumber = (str: string): number | null => {
  if (!str) return null;
  const clean = str.replace(/[^d.-]/g, '');
  if (!clean || clean === '-' || clean === '.') return null;
  const num = parseFloat(clean);
  if (isNaN(num)) return null;
  if (num < props.min) return props.min;
  if (num > props.max) return props.max;
  return num;
};// 监听外部 modelValue 变化
watch(() => props.modelValue, (val) => {
  if (!isFocused.value) {
    inputValue.value = toFormatted(val);
  }
});// 聚焦事件
const onFocus = (event: FocusEvent) => {
  isFocused.value = true;
  // 聚焦时显示纯数字,方便编辑
  const num = toNumber(inputValue.value);
  inputValue.value = num !== null ? num.toString() : '';
  emit('focus', event);
};// 失焦事件
const onBlur = (event: FocusEvent) => {
  isFocused.value = false;
  const num = toNumber(inputValue.value);
  inputValue.value = toFormatted(num);
  emit('update:modelValue', num);
  emit('blur', event);
};// 初始化
onMounted(() => {
  if (props.modelValue !== null && props.modelValue !== undefined) {
    inputValue.value = toFormatted(props.modelValue);
  }
});
</script><style scoped>
.currency-input {
  display: flex;
  flex-direction: column;
  margin-bottom: 12px;
}.label {
  margin-bottom: 4px;
  font-weight: 500;
  color: #333;
}.input-wrapper {
  position: relative;
}.currency-symbol {
  color: #999;
  font-size: 14px;
}
</style>

index.vue

 复制代码<template>
  <div>
    <CurrencyInput v-model="amount" label="金额" placeholder="请输入金额" currency="HKD" locale="zh-CN" :precision="4" append-mode="prefix"
      :min="0" :max="9999999" />
    <p>当前值:{{ amount }}</p>
  </div>
</template><script setup>
defineOptions({
  name: 'CurrencyInputIndex'
});import { ref } from 'vue';
import CurrencyInput from './CurrencyInput.vue';
import CurrencyInput1 from './CurrencyInput1.vue';const amount = ref(null);</script>

输入框左侧

输入框右侧

参考文献

API | Vue Currency Input

热门栏目