如何格式化Vuex绑定的v-model值,提交前移除格式并解决删除键触发问题?
解决Vuex绑定时间格式输入框时的实时更新问题
看起来你遇到的核心问题是v-model的实时触发机制——每次按键(包括退格、删除)都会调用计算属性的set方法,而且你的set方法还有个关键bug:你在解析时间的时候误用了Store里的旧值this.$store.state.athlete.swimFtp,而不是用户当前输入的value,这会直接导致计算结果完全错误!先把这个bug修复,再解决触发时机的问题。
下面给你几个实用的解决方案:
方案1:用lazy修饰符延迟更新(最简单高效)
Vuetify的v-text-field支持Vue原生的v-model.lazy修饰符,它会在输入框失去焦点或者用户按下回车键时才更新绑定值,完美避开了每次按键都触发set的问题。
修改后的输入框代码:
<v-text-field :label="$vuetify.t('$vuetify.swimFtp')" :hint="$vuetify.t('$vuetify.swimFtp')" mask="time-with-seconds" v-model.lazy="swimFtp" required > </v-text-field>
修正后的计算属性set方法:
set (value) { // 用用户输入的value解析,而不是Store旧值 const [hours, mins, secs] = value.split(':').map(Number); const totalSeconds = hours * 3600 + mins * 60 + secs; this.$store.commit('updateSwimFtp', totalSeconds); }
这个方案改动最小,完全匹配你的需求:只有用户确认输入(回车或失焦)时才更新Store。
方案2:手动绑定值+监听回车事件(更可控)
如果你想严格限制只有按下回车键才提交,可以放弃v-model,手动绑定显示值,用临时变量存储用户输入,再监听回车事件触发提交:
组件模板:
<v-text-field :label="$vuetify.t('$vuetify.swimFtp')" :hint="$vuetify.t('$vuetify.swimFtp')" mask="time-with-seconds" :value="formattedSwimFtp" @input="updateTempValue" @keydown.enter="submitToStore" required > </v-text-field>
组件脚本:
data() { return { tempInput: '' // 临时存储用户输入的时间字符串 } }, computed: { athlete() { return this.$store.state.athlete }, formattedSwimFtp() { // 和原来的get方法一致,格式化Store中的秒数 const date = new Date(null); date.setSeconds(this.athlete.swimFtp); return date.toISOString().substr(11, 8); } }, methods: { updateTempValue(value) { // 实时同步用户输入到临时变量 this.tempInput = value; }, submitToStore() { // 回车时解析并提交到Store const [hours, mins, secs] = this.tempInput.split(':').map(Number); const totalSeconds = hours * 3600 + mins * 60 + secs; this.$store.commit('updateSwimFtp', totalSeconds); } }
这个方案灵活性更高,你还可以额外添加一个“保存”按钮,把submitToStore绑定到按钮的点击事件上,给用户多一种提交选择。
方案3:优化计算属性的set方法(实时更新但避免错误)
如果你希望保持实时更新,但不想因为输入过程中的不完整格式(比如退格后输入未完成)导致错误值存入Store,可以在set方法里添加格式校验:
set (value) { // 校验输入是否符合##:##:##的格式 const validTimeRegex = /^\d{2}:\d{2}:\d{2}$/; if (!validTimeRegex.test(value)) { // 格式不合法时不更新Store return; } const [hours, mins, secs] = value.split(':').map(Number); const totalSeconds = hours * 3600 + mins * 60 + secs; this.$store.commit('updateSwimFtp', totalSeconds); }
这样即使用户在输入过程中触发了set,只要格式不完整,就不会把错误值写入Store。
内容的提问来源于stack exchange,提问作者Erick Audet
相关产品推荐
相关产品推荐

