vue组件中节流函数的失效的原因和解决方法


Posted in Vue.js onDecember 02, 2020

今天使用节流函数的时候遇见了一个问题,搞了半天才找到原因,所以在这里做个总结。

节流函数

浏览器的一些事件,如:resize,scroll,mousemove等。这些事件触发频率太过频繁,绑定在这些事件上的回调函数会不停的被调用,加重浏览器的负担,导致用户体验非常糟糕。所以先贤们发明了节流函数,简单版本如下:

function throttle (f, wait = 200) {
 let last = 0
 return function (...args) {
 let now = Date.now()
 if (now - last > wait) {
  last = now
  f.apply(this, args)
 }
 }
}

假设有一个 vue 组件 svgMark。这个组件中渲染的元素要在页面窗口大小发生变化时重绘 reDraw ,而重绘时要使用节流函数防止性能损耗。正常情况下代码如下:

<template>
 <div>{{ index }}</div>
</template>

<script>
import { throttle } from 'lodash'
export default {
 name: 'SvgMark',
 data() {
 return {
  index: 0
 }
 },
 mounted() {
 window.addEventListener('resize', this.reDraw)
 },
 beforeDestroy() {
 window.removeEventListener('resize', this.reDraw)
 },
 methods: {
 reDraw: throttle(function() {
  this.index++
 }, 500)
 }
}
</script>
</script>

一般情况下这样用没什么问题。但是有这样一个场景,使用节流函数时却失效了,即当这个组件被 v-for 循环加载了很多次:

<template>
 <div>
 <svgMark v-for="item in 10" :key="item.id" />
 </div>
</template>

这个时候无论渲染了多少个 svgMark 组件,在窗口大小改变的时候却只触发了第一个组件和第 n 割组件的重绘,为什么其他组件没有触发呢?这就要从头说起了。

  • 节流函数

节流函数在初始化的时候产生了一个闭包,闭包内保存了变量 last ,这个 last 记录了上一次执行 f 函数的时间。而当下一次触发节流函数的时候,如果此时时间 now 减去上次时间 last 小于了我们规定的节流时间 wait ,那么函数 f 将不会执行。

很显然,第一个子组件在触发节流函数的时候产生了一个 last,而第二个组件在触发节流函数时候的时产生的 now 并没有满足 now - last > wait 的条件,所以没有执行重绘代码。而到了第 n 个组件触发节流函数的时候,满足了 now - last > wait 的条件所以重绘成功了。

  • vue 组件

vue 组件在代码编译的阶段,组件 svgMark 中的方法 reDraw: throttle(function() { this.index++ }, 500) 就已经被编译成了类似如下函数:

reDraw: ƒ (...args) {
 let now = Date.now()
 if (now - last > wait) {
 last = now
 f.apply(this, args)
 }
}

由于函数是引用类型,所有使用子组件 svgMark 的 methods 中的 reDraw 都指向了同一个内存地址,也就是说所有子组件的 reDraw 方法都是同一个函数。

因为所有组件都公用了同一个节流函数,当然就会产生节流了。那怎么解决问题呢?对症下药就要让每个组件产生自己的节流函数,而不产生共用。代码如下

子组件:

<template>
 <div>{{ index }}</div>
</template>

<script>
import { throttle } from 'lodash'
export default {
 name: 'SvgMark',
 data() {
 return {
  index: 0
 }
 },
 mounted() {
 this.reDraw = throttle(() => {
  this.index++
 }, 500)
 window.addEventListener('resize', this.reDraw)
 },
 beforeDestroy() {
 window.removeEventListener('resize', this.reDraw)
 }
}
</script>

我们在 mounted 声明周期函数中手动声明了 reDraw 函数替代 methods 中的 reDraw ,这样在每个组件初始化的时候都会产生一个自己的节流函数了。需要注意此时节流函数的参数使用了箭头函数,因为这样 this 才会指向组件实例。

以上就是节流函数带给我的坑,现在分享给大家。[下班][鼓掌]

以上就是vue组件中节流函数的失效和解决方法的详细内容,更多关于vue 组件节流函数的资料请关注三水点靠木其它相关文章!

Vue.js 相关文章推荐
在vue中通过render函数给子组件设置ref操作
Nov 17 Vue.js
全面解析Vue中的$nextTick
Dec 24 Vue.js
vue使用require.context实现动态注册路由
Dec 25 Vue.js
vue实现一个获取按键展示快捷键效果的Input组件
Jan 13 Vue.js
vue首次渲染全过程
Apr 21 Vue.js
SSM VUE Axios详解
Oct 05 Vue.js
Vue+TypeScript中处理computed方式
Apr 02 Vue.js
vue3使用vuedraggable实现拖拽功能
Apr 06 Vue.js
vue实现可以快进后退的跑马灯组件
Apr 08 Vue.js
vue如何实现关闭对话框后刷新列表
Apr 08 Vue.js
vue3语法糖内的defineProps及defineEmits
Apr 14 Vue.js
Vue OpenLayer测距功能的实现
Apr 20 Vue.js
Vue3+elementui plus创建项目的方法
Dec 01 #Vue.js
Vue.js桌面端自定义滚动条组件之美化滚动条VScroll
Dec 01 #Vue.js
vue开发chrome插件,实现获取界面数据和保存到数据库功能
Dec 01 #Vue.js
vue实现表格合并功能
Dec 01 #Vue.js
vue element实现表格合并行数据
Nov 30 #Vue.js
Vue Elenent实现表格相同数据列合并
Nov 30 #Vue.js
vue中defineProperty和Proxy的区别详解
Nov 30 #Vue.js
You might like
php XMLWriter类的简单示例代码(RSS输出)
2011/09/30 PHP
浅析php插件 HTMLPurifier HTML解析器
2013/07/01 PHP
js 深拷贝函数
2008/12/04 Javascript
JavaScript 乱码问题
2009/08/06 Javascript
jquery遍历筛选数组的几种方法和遍历解析json对象
2013/12/13 Javascript
PHP使用方法重载实现动态创建属性的get和set方法
2014/11/17 Javascript
javascript批量修改文件编码格式的方法
2015/01/27 Javascript
JQ实现新浪游戏首页幻灯片
2015/07/29 Javascript
谈谈我对JavaScript原型和闭包系列理解(随手笔记9)
2015/12/24 Javascript
AngularJS 如何在控制台进行错误调试
2016/06/07 Javascript
关于javascript原型的修改与重写(覆盖)差别详解
2016/08/31 Javascript
js提示框替代系统alert,自动关闭alert对话框的实现方法
2016/11/07 Javascript
使用taro开发微信小程序遇到的坑总结
2019/04/08 Javascript
layui监听下拉选框选中值变化的方法(包含监听普通下拉选框)
2019/09/24 Javascript
JavaScript如何判断对象有某属性
2020/07/03 Javascript
JS闭包原理及其使用场景解析
2020/12/03 Javascript
[42:22]DOTA2上海特级锦标赛C组小组赛#1 OG VS Archon第一局
2016/02/27 DOTA
Python中使用第三方库xlutils来追加写入Excel文件示例
2015/04/05 Python
python复制文件到指定目录的实例
2018/04/27 Python
深入分析python中整型不会溢出问题
2018/06/18 Python
Python数据可视化之画图
2019/01/15 Python
对python 中class与变量的使用方法详解
2019/06/26 Python
Python MongoDB 插入数据时已存在则不执行,不存在则插入的解决方法
2019/09/24 Python
详解Anconda环境下载python包的教程(图形界面+命令行+pycharm安装)
2019/11/11 Python
Numpy将二维数组添加到空数组的实现
2019/12/05 Python
Python利用FFT进行简单滤波的实现
2020/02/26 Python
Python 串口通信的实现
2020/09/29 Python
Python学习工具jupyter notebook安装及用法解析
2020/10/23 Python
Html5插件教程之添加浏览器放大镜效果的商品橱窗
2016/01/07 HTML / CSS
基于HTML5的齿轮动画特效
2016/02/29 HTML / CSS
餐饮业员工工作决心书
2014/03/11 职场文书
我们的节日清明节活动总结
2014/04/30 职场文书
趣味运动会策划方案
2014/06/02 职场文书
局机关干部群众路线个人对照检查材料思想汇报
2014/10/05 职场文书
毕业生爱心捐书倡议书
2015/04/27 职场文书
六一晚会主持词开场白
2015/05/28 职场文书