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中activated的用法
Jan 03 Vue.js
如何在vue中使用HTML 5 拖放API
Jan 14 Vue.js
Vue实现摇一摇功能(兼容ios13.3以上)
Jan 26 Vue.js
Vue 3自定义指令开发的相关总结
Jan 29 Vue.js
vue浏览器返回监听的具体步骤
Feb 03 Vue.js
vue项目配置 webpack-obfuscator 进行代码加密混淆的实现
Feb 26 Vue.js
vue-router懒加载的3种方式汇总
Feb 28 Vue.js
使用vue-element-admin框架从后端动态获取菜单功能的实现
Apr 29 Vue.js
Vue接口封装的完整步骤记录
May 14 Vue.js
vue-router中hash模式与history模式的区别
Jun 23 Vue.js
vue使用wavesurfer.js解决音频可视化播放问题
Apr 04 Vue.js
vue报错function () { [native code] },无法出现我们想要的内容 Unknown custom element
Apr 11 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 网页过期时间的控制代码
2009/06/29 PHP
PHP父类调用子类方法的代码例子
2014/04/09 PHP
PHP 与 UTF-8 的最佳实践详细介绍
2017/01/04 PHP
thinkPHP5框架auth权限控制类与用法示例
2018/06/12 PHP
PHP code 验证码生成类定义和简单使用示例
2020/05/27 PHP
javascript hashtable实现代码
2009/10/13 Javascript
jQuery学习笔记 操作jQuery对象 属性处理
2012/09/19 Javascript
Javascript倒计时页面跳转实例小结
2013/09/11 Javascript
基于Bootstrap仿淘宝分页控件实现代码
2016/11/07 Javascript
深入浅析AngularJS中的一次性数据绑定 (bindonce)
2017/05/11 Javascript
Angular中管道操作符(|)的使用方法
2017/12/15 Javascript
javascript 通过键名获取键盘的keyCode方法
2017/12/31 Javascript
node.js部署之启动后台运行forever的方法
2018/05/23 Javascript
跟混乱的页面弹窗说再见
2019/04/11 Javascript
详解NodeJs项目 CentOs linux服务器线上部署
2019/09/16 NodeJs
vue实现表格合并功能
2020/12/01 Vue.js
[02:44]DOTA2英雄基础教程 克林克兹
2014/01/15 DOTA
用smtplib和email封装python发送邮件模块类分享
2014/02/17 Python
Python2.x利用commands模块执行Linux shell命令
2016/03/11 Python
Python tornado队列示例-一个并发web爬虫代码分享
2018/01/09 Python
python添加模块搜索路径和包的导入方法
2019/01/19 Python
解决python tkinter界面卡死的问题
2019/07/17 Python
Django框架静态文件使用/中间件/禁用ip功能实例详解
2019/07/22 Python
Python3爬虫中Selenium的用法详解
2020/07/10 Python
Python析构函数__del__定义原理解析
2020/11/20 Python
html5 sessionStorage会话存储_动力节点Java学院整理
2017/07/06 HTML / CSS
HTML5利用约束验证API来检查表单的输入数据的代码实例
2016/12/20 HTML / CSS
Blancsom美国/加拿大:服装和生活用品供应商
2018/07/27 全球购物
大学生毕业求职简历的自我评价
2013/10/24 职场文书
优秀团队获奖感言
2014/02/19 职场文书
生物技术专业求职信
2014/06/10 职场文书
装修施工安全责任书
2014/07/24 职场文书
金榜题名主持词
2015/07/02 职场文书
详解MySQL的半同步
2021/04/22 MySQL
《乙女游戏世界对路人角色很不友好》OP主题曲无字幕动画MV公开
2022/04/05 日漫
使用Ajax实现进度条的绘制
2022/04/07 Javascript