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-drawer-layout实现手势滑出菜单栏
Nov 19 Vue.js
Vue 的 v-model用法实例
Nov 23 Vue.js
详解Vue 的异常处理机制
Nov 30 Vue.js
通过vue.extend实现消息提示弹框的方法记录
Jan 07 Vue.js
vue自定义组件实现双向绑定
Jan 13 Vue.js
vue实现一个获取按键展示快捷键效果的Input组件
Jan 13 Vue.js
vue+echarts实现中国地图流动效果(步骤详解)
Jan 27 Vue.js
vue使用v-model进行跨组件绑定的基本实现方法
Apr 28 Vue.js
Vue Element UI自定义描述列表组件
May 18 Vue.js
vue3中provide && inject的使用
Jul 01 Vue.js
一定要知道的 25 个 Vue 技巧
Nov 02 Vue.js
Vue Element plus使用方法梳理
Dec 24 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树-不需要递归的实现方法
2016/06/21 PHP
php实现带读写分离功能的MySQL类完整实例
2016/07/28 PHP
微信网页授权(OAuth2.0) PHP 源码简单实现
2016/08/29 PHP
php中文乱码问题的终极解决方案汇总
2017/08/01 PHP
PHP设计模式之观察者模式定义与用法分析
2019/04/04 PHP
PHP单元测试配置与使用方法详解
2019/12/27 PHP
lib.utf.js
2007/08/21 Javascript
javascript 操作Word和Excel的实现代码
2009/10/26 Javascript
JavaScript 入门基础知识 想学习js的朋友可以参考下
2009/12/26 Javascript
firefox和IE系列的相关区别整理 以备后用
2009/12/28 Javascript
JavaScript 10件让人费解的事情
2010/02/15 Javascript
关于javascript中this关键字(翻译+自我理解)
2010/10/20 Javascript
lyhucSelect基于Jquery的Select数据联动插件
2011/03/29 Javascript
Javascript 中 null、NaN和undefined的区别总结
2013/04/10 Javascript
js实现头像图片切割缩放及无刷新上传图片的方法
2015/07/17 Javascript
简单谈谈node.js 版本控制 nvm和 n
2015/10/15 Javascript
Javascript技术栈中的四种依赖注入详解
2016/02/23 Javascript
功能强大的Bootstrap使用手册(一)
2016/08/02 Javascript
jQuery 的 ready()的纯js替代方法
2016/11/20 Javascript
微信小程序-图片、录音、音频播放、音乐播放、视频、文件代码实例
2016/11/22 Javascript
详解关于react-redux中的connect用法介绍及原理解析
2017/09/11 Javascript
Javascript中弹窗confirm与prompt的区别
2018/10/26 Javascript
深入理解令牌认证机制(token)
2019/08/22 Javascript
jquery检测上传文件大小示例
2020/04/26 jQuery
小程序自动化测试的示例代码
2020/08/11 Javascript
Windows下安装Scrapy
2018/10/17 Python
用python生成1000个txt文件的方法
2018/10/25 Python
Python拼接字符串的7种方法总结
2018/11/01 Python
python http基本验证方法
2018/12/26 Python
使用python实现语音文件的特征提取方法
2019/01/09 Python
Python解压 rar、zip、tar文件的方法
2019/11/19 Python
Python进行特征提取的示例代码
2020/10/15 Python
小学生操行评语
2014/04/22 职场文书
2016年公务员六五普法心得体会
2016/01/21 职场文书
导游词之安徽巢湖
2019/12/26 职场文书
Python time库的时间时钟处理
2021/05/02 Python