Vue中如何结合@input正确处理watch()监听逻辑?
Vue中v-model与@input执行顺序导致的watch触发问题
我需要基于@input触发的变量更新来处理v-model的变化,但遇到了Vue执行顺序的问题。以下是简化后的代码:
<script setup> import { ref, watch } from 'vue' const foo = ref(1) const bar = ref(1) const lorem = ref(false) const handleInput = (val) => { bar.value = val } watch(foo, (newFoo) => { if (bar.value === 2) { lorem.value = true } }) </script> <template> <input v-model="foo" @input="handleInput(2)"><br> {{foo}}<br> {{bar}}<br> {{lorem}} </template>
实际表现是:watch监听器会在handleInput方法执行前就触发。修改输入框的foo值时,只有第二次修改foo,lorem的值才会被设为true,但我希望它能立刻变为true。
我试过用nextTick()和flush: 'post'配置,但都没得到预期结果:
<script setup> import { ref, nextTick, watch } from 'vue' const foo = ref(1) const bar = ref(1) const lorem = ref(false) const handleInput = (val) => { nextTick(() => { bar.value = val }) } watch(foo, async (newFoo) => { await nextTick() if (bar.value === 2) { lorem.value = true } }, { flush: 'post' }) </script> <template> <input v-model="foo" @input="handleInput(2)"><br> {{foo}}<br> {{bar}}<br> {{lorem}} </template>
解决方案
问题出在Vue的执行顺序上:v-model是语法糖,它会在@input事件触发后更新绑定的响应式变量,但默认情况下,watch会在响应式变量更新后立即执行,这时候@input的回调还没跑完,bar的值还没被修改,所以watch里的判断不成立。
下面是两种可行的解决方法:
方法一:调整watch的触发时机
给watch加上flush: 'post'配置,让它在所有同步更新完成后再执行,此时handleInput已经修改了bar的值:
<script setup> import { ref, watch } from 'vue' const foo = ref(1) const bar = ref(1) const lorem = ref(false) const handleInput = (val) => { bar.value = val // 直接赋值,不用套nextTick } watch(foo, (newFoo) => { if (bar.value === 2) { lorem.value = true } }, { flush: 'post' }) // 关键:post模式延迟watch触发 </script> <template> <input v-model="foo" @input="handleInput(2)"><br> {{foo}}<br> {{bar}}<br> {{lorem}} </template>
方法二:直接在handleInput中处理逻辑
既然逻辑依赖于@input触发的bar更新,不如把watch里的判断直接移到handleInput里,彻底避开执行顺序问题:
<script setup> import { ref } from 'vue' const foo = ref(1) const bar = ref(1) const lorem = ref(false) const handleInput = (val) => { bar.value = val // 直接在这里判断赋值 if (bar.value === 2) { lorem.value = true } } </script> <template> <input v-model="foo" @input="handleInput(2)"><br> {{foo}}<br> {{bar}}<br> {{lorem}} </template>
两种方法都能实现修改foo时lorem立刻变为true的效果,按需选择即可。
内容的提问来源于stack exchange,提问作者DirkReuter
相关产品推荐
相关产品推荐

