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项目利用axios请求接口下载excel
Nov 17 Vue.js
Vue3配置axios跨域实现过程解析
Nov 25 Vue.js
vuex页面刷新导致数据丢失的解决方案
Dec 10 Vue.js
vue实现一个获取按键展示快捷键效果的Input组件
Jan 13 Vue.js
vue 组件基础知识总结
Jan 26 Vue.js
vue使用transition组件动画效果的实例代码
Jan 28 Vue.js
用vite搭建vue3应用的实现方法
Feb 22 Vue.js
vue前端工程的搭建
Mar 31 Vue.js
vue+elementui 实现新增和修改共用一个弹框的完整代码
Jun 08 Vue.js
Vue实现导入Excel功能步骤详解
Jul 03 Vue.js
Vue3中toRef与toRefs的区别
Mar 24 Vue.js
解决vue-router的beforeRouteUpdate不能触发
Apr 14 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
当海贼王变成JOJO风
2020/03/02 日漫
DedeCms模板安装/制作概述
2007/03/11 PHP
完美解决PHP中的Cannot modify header information 问题
2013/08/12 PHP
php中多维数组按指定value排序的实现代码
2014/08/19 PHP
javascript dom 操作详解 js加强
2009/07/13 Javascript
一个简单的js渐显(fadeIn)渐隐(fadeOut)类
2010/06/19 Javascript
Textbox控件注册回车事件及触发按钮提交事件具体实现
2013/03/04 Javascript
JS遍历Json字符串中键值对先转成JSON对象再遍历
2014/08/15 Javascript
如何调试异步加载页面里包含的js文件
2014/10/30 Javascript
js继承call()和apply()方法总结
2014/12/08 Javascript
jQuery插件formValidator自定义函数扩展功能实例详解
2015/11/25 Javascript
vue源码入口文件分析(推荐)
2018/01/30 Javascript
JavaScript实现动态添加、移除元素或属性的方法分析
2019/01/03 Javascript
如何解决.vue文件url引用文件的问题
2019/01/18 Javascript
JavaScript数据结构与算法之二叉树插入节点、生成二叉树示例
2019/02/21 Javascript
vue基础知识--axios合并请求和slot
2020/06/04 Javascript
js实现翻牌小游戏
2020/07/31 Javascript
JavaScript数组排序的六种常见算法总结
2020/08/18 Javascript
JavaScript中的几种继承方法示例
2020/12/06 Javascript
Python删除指定目录下过期文件的2个脚本分享
2014/04/10 Python
python optparse模块使用实例
2015/04/09 Python
Python使用dis模块把Python反编译为字节码的用法详解
2016/06/14 Python
django轻松使用富文本编辑器CKEditor的方法
2017/03/30 Python
python中的变量如何开辟内存
2018/06/26 Python
使用sklearn进行对数据标准化、归一化以及将数据还原的方法
2018/07/11 Python
Python日期时间模块datetime详解与Python 日期时间的比较,计算实例代码
2018/09/14 Python
强悍的Python读取大文件的解决方案
2019/02/16 Python
python GUI库图形界面开发之PyQt5信号与槽机制、自定义信号基础介绍
2020/02/25 Python
pytorch  网络参数 weight bias 初始化详解
2020/06/24 Python
美国知名艺术画网站:Art.com
2017/02/09 全球购物
Derek Rose官网:英国高档睡衣、家居服和内衣品牌
2020/01/18 全球购物
总务岗位职责
2013/11/19 职场文书
房地产融资计划书
2014/01/10 职场文书
写给女生的道歉信
2014/01/14 职场文书
yy生日主持词
2014/03/20 职场文书
如何用JavaScript实现一个数组惰性求值库
2021/05/05 Javascript