Vue中如何阻止v-model输入框即时更新,待用户输完参数再触发绘制
Vue输入时重复触发Canvas网格绘制的解决方法
问题原因
v-model默认绑定input事件,输入框每输入一个字符就会同步更新绑定值,通过watch监听宽高变化直接触发绘制逻辑,就会导致输入过程中反复执行draw函数:例如输入57时,输入字符5就会触发一次宽度为5的网格绘制,输入到57时又触发一次宽度为57的绘制,最终出现多层网格叠加的问题。
之前尝试的固定延迟setTimeout(draw, 3000)不生效,核心原因是每次值变化都会新建一个定时器,没有清除上一次未执行的定时任务,多个定时器到点后会依次执行绘制。
可选实现方案
方案1:使用v-model.lazy修饰符
v-model.lazy会将值同步的触发时机从input事件改为change事件,也就是输入框失焦、用户按下回车确认输入时才会更新绑定值,天然匹配「用户输完再触发更新」的需求,用法非常简单:
<input type="number" v-model.lazy="cols" placeholder="输入网格列数(宽度)"> <input type="number" v-model.lazy="rows" placeholder="输入网格行数(高度)">
如果使用该修饰符未生效,先检查输入框是否为自定义封装组件:自定义组件需要正确透传原生
change事件才能让.lazy修饰符正常工作,原生input元素可直接使用。
方案2:防抖触发(停止输入后自动绘制)
如果希望用户不用点确认、停止输入一小段时间后自动触发绘制,可以用防抖逻辑优化定时器写法,每次输入新内容时清除上一次未执行的绘制任务:
// 存储定时器标识 let drawTimer = null export default { watch: { cols() { this.scheduleDraw() }, rows() { this.scheduleDraw() } }, methods: { scheduleDraw() { // 清除上一次未执行的绘制任务 if (drawTimer) clearTimeout(drawTimer) // 用户停止输入300ms后再执行绘制,延迟时间可根据需求调整 drawTimer = setTimeout(() => { this.draw() }, 300) }, draw() { // 绘制前必须先清空画布上的旧网格,避免内容叠加 tiles.removeAllChildren() for (let j = 0; j < this.rows; j++) { for (let i = 0; i < this.cols; i++) { const tile = new Rectangle({ width: size, height: size, borderColor: "#a8a8a8", borderWidth: 0.2 }) .centerReg(tiles) .loc(size / 2 + i * size, size / 2 + j * size); } } } } }
方案3:显式按钮确认触发(逻辑最稳定)
如果需要完全避免输入过程中的误触发,可以去掉watch里的绘制触发逻辑,增加确认按钮,用户输完所有参数主动点击后再执行绘制:
<input type="number" v-model="cols" placeholder="输入网格列数"> <input type="number" v-model="rows" placeholder="输入网格行数"> <button @click="draw">生成网格</button>
注意事项
- 每次执行绘制逻辑前,必须先清空画布上已存在的旧网格元素,否则即使触发时机正确,旧内容残留也会出现多层网格叠加的问题
- 针对数字输入框要增加基础合法性校验,避免输入0、负数、非数字值时执行绘制导致逻辑报错
内容的提问来源于stack exchange,提问作者mustafa00
相关产品推荐
相关产品推荐

