Vuetify v-text-field金额格式化失焦后显示旧值问题求助
失焦后金额输入组件显示旧值的原因及修复方案
问题原因
- 双向绑定逻辑混乱:你同时混用了Vue 2的
model选项(绑定value和input事件)与Vue 3风格的@update:model-value事件,两种v-model语法冲突,导致失焦时重复触发值更新操作,新值被旧值覆盖。 betrag与Imask实例同步错误:父组件更新betrag时,watch直接设置masked.unmaskedValue,但未确保输入框显示的格式化值同步更新;同时失焦时触发的emit会再次触发watch,将旧值重新塞回Imask,造成显示回退。- 输入框绑定值未实时响应:
v-text-field的model-value绑定的是masked.value,但Imask内部值变化后,输入框未实时更新;当失焦父组件更新betrag时,watch触发导致显示回到旧值。
修复方案
1. 统一双向绑定逻辑
移除Vue 3风格的@update:model-value事件,仅使用Vue 2的model选项,将prop直接绑定到betrag,确保绑定逻辑一致。
2. 优化betrag与Imask的同步逻辑
- 监听
betrag时先判断Imask实例是否初始化,避免报错; - 利用Imask自带的
onAccept事件自动同步未掩码值到父组件,替代手动在input和blur事件中重复emit。
3. 确保输入框实时显示最新值
添加计算属性处理显示值,初始化前展示格式化后的betrag,初始化后展示Imask的格式化值,保证任何场景下显示正确。
修改后的完整代码
<template> <v-container class="pa-0" v-if="$attrs.editable"> <v-text-field ref="field" :model-value="displayValue" @blur="handleBlur" v-bind="$attrs" density="compact" variant="outlined" ></v-text-field> </v-container> <v-container class="pa-0" v-else> {{ formatBetrag(betrag) }} </v-container> </template> <script lang="ts"> import Imask from 'imask' const INPUT_EVENT = 'input' export default { name: 'ImaskField', components: { BetragsFeld }, model: { prop: 'betrag', event: INPUT_EVENT }, props: { betrag: { type: [String, Number], required: false, default: 0 }, }, computed: { displayValue() { // 初始化前返回格式化后的金额 if (!this.masked) { return this.formatBetrag(this.betrag) } return this.masked.value } }, data: () => ({ element: null, masked: null, }), watch: { betrag(val) { if (this.masked) { // 仅当值不同时更新,避免循环触发 if (String(this.masked.unmaskedValue) !== String(val)) { this.masked.unmaskedValue = String(val) } } } }, methods: { formatBetrag(value) { if (value === undefined || value === null) return '' return Number(value).toLocaleString('de-DE', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) }, init() { this.element = this.$refs.field.$el.querySelector('input') this.masked = Imask(this.element, { mask: Number, thousandsSeparator: '.', scale: 2, padFractionalZeros: true, normalizeZeros: true, radix: ',', // 用Imask自带事件同步值到父组件 onAccept: () => { const unmaskedValue = Number(this.masked.unmaskedValue) this.$emit(INPUT_EVENT, unmaskedValue) } }) // 初始化时设置初始值 this.masked.unmaskedValue = String(this.betrag) }, handleBlur() { // 失焦时确保值规范化并强制更新显示 if (this.masked) { this.masked.updateValue() this.$forceUpdate() } } }, mounted() { if (this.$attrs.editable) { // 延迟初始化确保DOM渲染完成 this.$nextTick(() => this.init()) } } } </script>
内容的提问来源于stack exchange,提问作者Jens
相关产品推荐
相关产品推荐

