「前端优化必学」v-model 陷阱,连续输入瞬间卡半天?!

v-model 是 Vue 中最常用的属性之一,它可以实现数据和表单元素的双向绑定,让我们的开发更加方便。

但是你知道吗?在绑定文本框时,如果不注意使用方式,v-model 会带来严重的性能问题。这些问题可能会影响用户体验,比如页面卡顿、动画元素闪动等。

那么,这些问题是怎么产生的呢?又该如何解决呢?

我是渡一前端子辰老师,今天我们一起来探究一下吧

问题产生的原因

我们先来看一个例子,我们有一个输入框和一个列表,输入框使用了 v-model 绑定了一个数据,列表使用了 Vue 的列表过渡效果,还有一个按钮可以对列表进行随机排序。

我们可以看到,当我们点击按钮进行随机排序时,列表的过渡效果很流畅。

但是,如果我们在随机排序的同时,在输入框中连续输入文字,会发生什么呢?

我们可以看到,当我们连续输入文字时,列表的过渡效果变得非常卡顿,当我们停止输入后,过渡效果又恢复正常。

这是为什么呢?其实原因很简单,就是因为 v-model 的双向绑定机制。v-model 其实是 :value + @input 组合的语法糖,也就是说,当文本框的值发生变化时,会触发 @input 事件,并更新绑定的数据。

而当数据发生变化时,Vue 会重新渲染组件,并更新文本框的值。

这样一来,如果我们在文本框中频繁输入文字,就会导致组件频繁重新渲染。

如果我们手速很快,一秒钟可以输入几十个字,那么组件就会在一秒钟内渲染几十次。

而组件的渲染其实是一个 JS 行为,而 JS 的执行会阻塞浏览器的其他动作,比如动画效果。

所以当组件渲染太频繁时,就会造成页面卡顿和动画闪动。

我们可以用浏览器的 Performance 工具来验证一下这个原因。

我们在输入框中输入了 12345 五个数字,并记录了性能数据。

从上图中我们可以看到,在输入框中每输入一个数字,都会触发一次组件的重新渲染。连续输入了 12345 五个数字,就导致了重新渲染五次。

你可能会奇怪,Vue 不是说过它在更新 DOM 时是异步执行的吗?它不是说它会开启一个队列,并缓冲在同一事件循环中发生的所有数据变更吗?它不是说如果同一个 watcher 被多次触发,只会被推入到队列中一次吗?

为什么 v-model 就不遵循这个规则呢?

其实这是因为 v-model 的实现机制和所说的响应式不太一样,v-model 其实是 :value + @input 组合的语法糖,当文本框 change 时会触发 watch 与 computed 函数,属性的变化走的是 defineProperty。而 watcher 走的是观察者模式,所以才用到了队列。

那么既然知道了问题产生的原因,我们就可以想办法解决它了。

问题解决的方法

其实解决这个问题很简单,只要让 v-model 不要那么敏感就行了。

也就是说,不要让它每次文本框的值变化就去更新数据和重新渲染组件,而要让它在合适的时机去做这些事情。

那么什么时候是合适的时机呢?答案是:当文本框失去焦点时。

也就是说,当用户完成了输入,并点击了其他地方或者按下了回车键时,才去更新数据和重新渲染组件。

这样就可以大大减少组件渲染的频率,并避免页面卡顿和动画闪动。

那么如何让 v-model 在文本框失去焦点时才更新数据和重新渲染组件呢?

其实很简单,只要给 v-model 加上一个修饰符 v-model.lazy 就行了。这个修饰符可以让 v-model 监听文本框的 change 事件而不是 input 事件。

也就是说,在文本框失去焦点时才触发事件,并更新数据和重新渲染组件。

xml 复制代码
<!-- v-model -->
<input v-model="..." />
<!-- v-model 就是 :value + @input 组合的语法糖-->
<input :value="..." @input="..." />
<!-- 当加了 .lazy 修饰符之后 -->
<input v-model.lazy="..." />
<!-- v-model 就变成了 :value + @change 组合的语法糖 -->
<input :value="..." @change="..." />

我们来看看加上这个修饰符后的效果吧。

从上图中我们可以看到,在随机排序期间无论我们怎么输入文字都不会影响动画效果了。

因为此时没有触发任何事件或者重新渲染组件。

只有当我们点击其他地方或者按下回车键后才会更新数据和重新渲染组件。

当然这种方法也有一个缺点,就是在一段时间内数据和文本框显示的内容不一致。

比如下图所示:

总结

通过这个例子我们可以学习到一个重要的优化技巧:减少不必要的组件重新渲染。

有时候我们可能不注意使用方式或者场景需求而导致组件重新渲染太频繁而影响性能和用户体验。

所以我们要根据具体情况具体分析,在保证功能正常运行的前提下尽量减少组件重新渲染的次数。

当然这只是 Vue 中众多优化技巧中的一小部分,Vue 还有很多其他优化技巧等待你去探索和学习。

本文来源

本文来源自渡一官方公众号:Duing ,欢迎关注,获取最新最全最深入的技术讲解

感谢你阅读本文,如果你有任何疑问或建议,请在评论区留言,如果你觉得这篇文章有用,请点赞收藏或分享给你的朋友!

相关推荐
廖子默9 分钟前
提供html2canvas+jsPDF将HTML页面以A4纸方式导出为PDF后,内容分页时存在截断的解决思路
前端·pdf·html
Moment11 分钟前
毕业半年,终于拥有了两个近 500 star 的开源项目了 🤭🤭🤭
前端·后端·开源
光影少年41 分钟前
react和vue图片懒加载及实现原理
前端·vue.js·react.js
AndyGoWei43 分钟前
react react-router-dom history 实现原理,看这篇就够了
前端·javascript·react.js
胡图蛋.1 小时前
vue的理解
vue.js
小仓桑1 小时前
深入理解 JavaScript 中的 AbortController
前端·javascript
摸鱼也很难1 小时前
解决 node.js 执行 npm下载 报无法执行脚本的错
前端·npm·node.js
换个名字不能让人发现我在摸鱼1 小时前
裁剪保存的图片黑边问题
前端·javascript
PeterJXL1 小时前
pnpm:包管理的新星,平替 npm 和 yarn
前端·npm·node.js·pnpm