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使用vant中的checkbox实现全选功能
Nov 17 Vue.js
vue表单验证之禁止input输入框输入空格
Dec 03 Vue.js
vue3.0中友好使用antdv示例详解
Jan 05 Vue.js
基于VUE实现简单的学生信息管理系统
Jan 13 Vue.js
vue+element table表格实现动态列筛选的示例代码
Jan 14 Vue.js
vue实现按钮切换图片
Jan 20 Vue.js
Vue看了就会的8个小技巧
Jan 21 Vue.js
vue3 watch和watchEffect的使用以及有哪些区别
Jan 26 Vue.js
学习 Vue.js 遇到的那些坑
Feb 02 Vue.js
vue2实现provide inject传递响应式
May 21 Vue.js
vue项目如何打包之项目打包优化(让打包的js文件变小)
Apr 30 Vue.js
vue实现在data里引入相对路径
Jun 05 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解析字符串里所有URL地址的方法
2015/04/03 PHP
PHP类型约束用法示例
2016/09/28 PHP
dwr spring的集成实现代码
2009/03/22 Javascript
js实现兼容IE6与IE7的DIV高度
2010/05/13 Javascript
JAVASCRIPT车架号识别/验证函数代码 汽车车架号验证程序
2012/01/08 Javascript
jQuery UI Autocomplete 1.8.16 中文输入修正代码
2012/04/16 Javascript
jquery聚焦文本框与扩展文本框聚焦方法
2012/10/12 Javascript
控制文字内容的显示与隐藏示例
2014/06/11 Javascript
JavaScript父子窗体间的调用方法
2015/03/31 Javascript
js实现文字在按钮上滚动的方法
2015/08/20 Javascript
js实现类似菜单风格的TAB选项卡效果代码
2015/08/28 Javascript
关于JS中prototype的理解
2015/09/07 Javascript
javascript每日必学之多态
2016/02/23 Javascript
js编写一个简单的产品放大效果代码
2016/06/27 Javascript
vue.js入门教程之绑定class和style样式
2016/09/02 Javascript
JavaScript正则替换HTML标签功能示例
2017/03/02 Javascript
用vue封装插件并发布到npm的方法步骤
2017/10/18 Javascript
vue 实现 ios 原生picker 效果及实现思路解析
2017/12/06 Javascript
微信小程序switch开关选择器使用详解
2018/01/31 Javascript
JS 实现缓存算法的示例(FIFO/LRU)
2018/03/20 Javascript
浅谈如何使用webpack构建多页面应用
2018/05/30 Javascript
vue非父子组件通信问题及解决方法
2018/06/11 Javascript
基于vue开发微信小程序mpvue-docs跳转页面功能
2019/04/10 Javascript
vue实现五子棋游戏
2020/05/28 Javascript
js实现简易拖拽的示例
2020/10/26 Javascript
python实现log日志的示例代码
2018/04/28 Python
Django中的cookie和session
2019/08/27 Python
Python爬虫:Request Payload和Form Data的简单区别说明
2020/04/30 Python
python 输入字符串生成所有有效的IP地址(LeetCode 93号题)
2020/10/15 Python
python调用百度AI接口实现人流量统计
2021/02/03 Python
css3和jquery实现的可折叠导航菜单适合放在手机网页的导航菜单
2014/09/02 HTML / CSS
新西兰购物网站:TheMarket NZ
2020/09/19 全球购物
说一下Linux下有关用户和组管理的命令
2014/08/18 面试题
ktv中秋节活动方案
2014/01/30 职场文书
秋季校运动会广播稿
2014/02/23 职场文书
关于读书的演讲稿1000字
2014/08/27 职场文书