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+iview实现分页及查询功能
Nov 17 Vue.js
Vue项目利用axios请求接口下载excel
Nov 17 Vue.js
解决vue elementUI 使用el-select 时 change事件的触发问题
Nov 17 Vue.js
Vue实现小购物车功能
Dec 21 Vue.js
vue 实现click同时传入事件对象和自定义参数
Jan 29 Vue.js
vue使用lodop打印控件实现浏览器兼容打印的方法
Feb 07 Vue.js
Vue基本指令实例图文讲解
Feb 25 Vue.js
vue打开新窗口并实现传参的图文实例
Mar 04 Vue.js
详解vue身份认证管理和租户管理
May 25 Vue.js
vue-cropper插件实现图片截取上传组件封装
May 27 Vue.js
VUE中的v-if与v-show区别介绍
Mar 13 Vue.js
vue3 自定义图片放大器效果的示例代码
Jul 23 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
无线电的诞生过程
2021/03/01 无线电
php读取3389的脚本
2014/05/06 PHP
PHP模块memcached使用指南
2014/12/08 PHP
PHP实现格式化文件数据大小显示的方法
2015/01/03 PHP
php获取从百度、谷歌等搜索引擎进入网站关键词的方法
2015/07/08 PHP
php结合ajax实现手机发红包的案例
2016/10/13 PHP
TNC vs BOOM BO3 第三场2.13
2021/03/10 DOTA
Prototype中dom对象方法汇总
2008/09/17 Javascript
ExtJS GTGrid 简单用户管理
2009/07/01 Javascript
javascript垃圾收集机制与内存泄漏详细解析
2013/11/11 Javascript
JS小功能(checkbox实现全选和全取消)实例代码
2013/11/28 Javascript
JavaScript使用shift方法移除素组第一个元素实例分析
2015/04/06 Javascript
原生javascript 学习之js变量全面了解
2016/07/14 Javascript
老生常谈原生JS执行环境与作用域
2016/11/22 Javascript
Java中int与integer的区别(基本数据类型与引用数据类型)
2017/02/19 Javascript
基于vue 动态加载图片src的解决方法
2018/02/05 Javascript
es6 symbol的实现方法示例
2019/04/02 Javascript
vue+element获取el-table某行的下标,根据下标操作数组对象方式
2020/08/07 Javascript
vue项目中播放rtmp视频文件流的方法
2020/09/17 Javascript
[01:08]DOTA2次级职业联赛 - Wings 战队宣传片
2014/12/01 DOTA
Python的消息队列包SnakeMQ使用初探
2016/06/29 Python
python自带的http模块详解
2016/11/06 Python
Python中函数及默认参数的定义与调用操作实例分析
2017/07/25 Python
python关于调用函数外的变量实例
2019/12/26 Python
Pytorch模型转onnx模型实例
2020/01/15 Python
一款基于css3的列表toggle特效实例教程
2015/01/04 HTML / CSS
百联网上商城:i百联
2017/01/28 全球购物
世界最大的海报和艺术印刷商店:AllPosters.com
2017/02/01 全球购物
《阳光》教学反思
2014/02/23 职场文书
会计电算化毕业生自荐信
2014/03/03 职场文书
2014年感恩母亲演讲稿
2014/05/27 职场文书
2014年初中班主任工作总结
2014/11/08 职场文书
文艺节目主持词
2015/07/06 职场文书
2015年董事长秘书工作总结
2015/07/23 职场文书
2015教师个人年度工作总结
2015/10/23 职场文书
在Django中使用MQTT的方法
2021/05/10 Python