Vue - 使用Lodash实现防抖和节流

news2024/11/28 16:52:51

GitHub Demo 地址

在线预览

Lodash 官网

参考:

Vue 防抖节流 详细介绍
vue 优雅的实现防抖和节流
防抖、节流的介绍
js防抖和节流的实现原理及应用场景
js防抖节流应用场景及写法
JS中的防抖

什么的防抖和节流?

函数节流(throttle)与 函数防抖(debounce)都是为了限制函数的执行频次,以优化函数触发频率过高导致的响应速度跟不上触发频率,出现延迟,假死或卡顿的现象
是应对频繁触发事件的优化方案。

防抖(debounce)

防抖就是防止抖动,避免事件的重复触发。
防抖可以概括为触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。
n 秒后执行该事件,若在n秒后被重复触发,则重新计时
简单的说,如果某一事件被连续快速地触发多次,只会执行最后那一次。

  • 实现方式:每次触发事件时设置一个延迟调用方法,并且取消之前的延时调用方法
  • 如果事件在规定的时间间隔内被不断的触发,则调用方法会被不断的延迟

使用场景

  • input 搜索录入,用户不断录入值
  • window触发resize事件
  • mousemove 鼠标滑动事件
  • scroll滚动条滑动请求、上拉触底加载更多
  • 表单验证,按钮的提交事件

节流(throttle)

节流就是减少流量,将频繁触发的事件减少,并每隔一段时间执行。会控制事件触发的频率。所以节流会稀释函数的执行频率。
n 秒内只运行一次,若在n秒内重复触发,只有一次生效。
如果连续快速地触发多次,在规定的时间内,只触发一次。如限制1s,则1s内只执行一次,无论怎样,都在会1s内执行相应的操作。

  • 实现方式:每次触发事件时,如果当前有等待执行的延时函数,则直接return
  • 如果事件在规定的时间间隔内被不断的触发,则调用方法在规定时间内都会执行一次

使用场景

  • 获取验证码
  • 鼠标不断点击触发,mousedown(规定时间内只触发一次)
  • mousemove 鼠标滑动事件
  • 滚动条滑动请求、上拉触底加载更多
  • 搜索、提交等按钮功能

防抖和节流之间的差别:

相同点:

  • 都可以通过使用 setTimeout 实现
  • 目的都是,降低回调函数的执行频率,节省计算资源

不同点:

  • 防抖,是在一段连续操作结束之后,处理回调,利用 clearTimout 和 setTimeout 实现。

  • 节流,是在一段连续操作中,每一段时间只执行一次,在频率较高的事件中使用来提高性能。

  • 防抖用于无法预知的用户主动行为,如用户输入内容去服务端动态搜索结果。用户打字的速度等是无法预知的,具有非规律性。

  • 节流可用于一些非用户主动行为或者可预知的用户主动行为,如用户滑动商品橱窗时发送埋点请求、滑动固定的高度是已知的逻辑,具有规律性。

  • 防抖是关注于最后一次的事件触发,而节流则是在规定的时间里只执行一次。

  • 防抖是将多次执行变为最后一次执行,节流是将多次执行变成每隔一段时间执行

防抖和节流 utils

/**
 * 防抖  (传入所要防抖的方法/回调与延迟时间)
 * @param {Function} func
 * @param {number} delay
 * @return {*}
 */
export function debounce2(func, delay) {
  let timer = null
  // 借助闭包,使得变量timer不被回收
  return function() {
    // 保存当前环境下的实例对象,this即为引入该方法的那个组件实例对象
    const th = this
    // 保存传入参数
    const args = arguments
    // 第一次timer为null,跳过该判断,执行setTimeout()
    if (timer) {
      // 之后如果timer存在,则把上一次的销毁,也就是setTimeout(),则里面的函数执行也会抛弃
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
      // apply(),改变this指向,指向正在操作的组件实例,传入参数
      func.apply(th, args)
      timer = null
    }, delay)
  }
}

/*
  由于使用闭包,使得timer不被回收,在A组件中每次调用该方法时会去判断timer是否存在,如果存在,
  表示上一次输入在等待执行fn(),期间如果继续输入,且在1s内,则会把上一次未执行的(setTimeout中的)fn()销毁,
  重新定时1s,以此来达到输入结束过1s才执行fn(),即触发事件或者发送请求。
*/

/**
 * 节流  (传入所要节流的方法/回调与延迟时间)
 * @param {Function} func
 * @param {number} delay
 * @return {*}
 */
export function throttle(func, delay) {
  let flag = true
  return function() {
    const th = this
    const args = arguments
    if (!flag) {
      // 未超过时间间隔,flag无效,不执行fn
      return false
    }
    func.apply(th, args)
    flag = false // 在时间间隔内把状态位flag设为无效(false)
    setTimeout(() => {
      flag = true // 超过时间间隔把状态位flag设为有效(true)
    }, delay)
  }
}

Lodash 安装

浏览器环境:

<script src="lodash.js"></script>

通过 npm:

$ npm i -g npm
$ npm i --save lodash

Lodash 防抖函数debounced 文档
Lodash 节流函数throttle 文档

使用Lodash实现防抖和节流

未处理时,录入文字改变就会触发一次事件,或者点击一次就会触发一次事件

在这里插入图片描述

处理后
录入文字使用的防抖,设置的0.5秒间隔,点击多次只在最后一次触发
点击查询按钮使用的节流,设置的3秒间隔,点击多次3秒内只会触发一次

在这里插入图片描述

防抖关键代码

 <el-input v-model="queryParams2.name" maxlength="20" placeholder="请输入" 
 clearable @input="onChange2" @keyup.enter.native="onSearch2" />

// lodash文档: https://www.lodashjs.com/
//
// 搜索框防抖 - lodash实现
// 不要在debounce里写箭头函数,否则this的指向就是undefined,而不是Vue实例对象。
// 注意这里若是使用箭头函数的话, this为 undefined https://github.com/vue-styleguidist/vue-docgen-api/issues/23
onChange2: lodash.debounce(function() {
  // Do some things
  this.getListByKeyword()
}, 500),
getListByKeyword() {
  // 请求...
  console.log('根据关键字 请求...')
  console.log(this.queryParams2.name)
  console.log(JSON.stringify(this.queryParams2))
},

节流关键代码 - 方式1

<el-button class="spp-form-btn" size="small" type="primary" @click="onSearch2()">查询</el-button>

 // 按钮节流 - lodash实现 - 方式1
 onSearch2: lodash.throttle(function() {
   // Do some things
   this.requestList()
 }, 3000),
 requestList() {
   // 请求...
   console.log('点击搜索按钮 请求...')
   console.log(JSON.stringify(this.queryParams2))
 },

节流关键代码 - 方式2

 <el-button class="spp-form-btn" size="small" type="primary" style="width: 120px;" 
 @click="onSearch22()">查询(方式2</el-button>

created() {
  // 按钮节流 - lodash实现 - 方式2
  this.onSearch22 = lodash.throttle(this.onSearch22, 3000)
},

requestList() {
  // 请求...
  console.log('点击搜索按钮 请求...')
  console.log(JSON.stringify(this.queryParams2))
},
// 按钮节流 - lodash实现 - 方式2
onSearch22() {
  // Do some things
  this.requestList3()
},

全部代码

<template>

  <div class="spp-theme-body spp-theme-pad">
  
    <h1 style="margin:10px 0px 30px;">防抖与节流</h1>
    
    <div> 未处理前 </div>
    <el-form :inline="true" size="small" :model="queryParams" class="spp-form-search spp-theme-top">
      <el-form-item>
        <span class="spp-form-label" style="width:80px">
          <i class="icon" /><i class="label">名称:</i>
        </span>
        <el-input v-model="queryParams.name" maxlength="20" placeholder="请输入" clearable @input="onChange" @keyup.enter.native="onSearch" />
      </el-form-item>
      <el-form-item>
        <el-button class="spp-form-btn" size="small" type="primary" @click="onSearch()">查询</el-button>
      </el-form-item>
    </el-form>

    <div class="spp-theme-top"> lodash实现 - 搜索框防抖(0.5秒) / 点击按钮节流(3秒内) </div>
    <el-form :inline="true" size="small" :model="queryParams2" class="spp-form-search spp-theme-top">
      <el-form-item>
        <span class="spp-form-label" style="width:80px">
          <i class="icon" /><i class="label">名称:</i>
        </span>
        <el-input v-model="queryParams2.name" maxlength="20" placeholder="请输入" clearable @input="onChange2" @keyup.enter.native="onSearch2" />
      </el-form-item>
      <el-form-item>
        <el-button class="spp-form-btn" size="small" type="primary" @click="onSearch2()">查询</el-button>
      </el-form-item>
      <el-form-item>
        <el-button class="spp-form-btn" size="small" type="primary" style="width: 120px;" @click="onSearch22()">查询(方式2</el-button>
      </el-form-item>
    </el-form>

    <div class="spp-theme-top"> utils实现 - 搜索框防抖(0.5秒) / 点击按钮节流(3秒内) </div>
    <el-form :inline="true" size="small" :model="queryParams2" class="spp-form-search spp-theme-top">
      <el-form-item>
        <span class="spp-form-label" style="width:80px">
          <i class="icon" /><i class="label">名称:</i>
        </span>
        <el-input v-model="queryParams3.name" maxlength="20" placeholder="请输入" clearable @input="onChange3" @keyup.enter.native="onSearch3" />
      </el-form-item>
      <el-form-item>
        <el-button class="spp-form-btn" size="small" type="primary" @click="onSearch3()">查询</el-button>
      </el-form-item>
    </el-form>

  </div>

</template>

<script>
import lodash from 'lodash'
import { debounce2, throttle } from '@/utils/index'

export default {
  components: {},
  data() {
    return {
      tableHeight: 170,
      tableLoading: false,
      tableData: [],
      queryParams: {
        name: '',
        page: 1,
        limit: this.pageGroup.size
      },
      queryParams2: {
        name: '',
        page: 1,
        limit: this.pageGroup.size
      },
      queryParams3: {
        name: '',
        page: 1,
        limit: this.pageGroup.size
      }
    }
  },
  created() {
    // 按钮节流 - lodash实现 - 方式2
    this.onSearch22 = lodash.throttle(this.onSearch22, 3000)
  },
  mounted() {},
  methods: {
    onChange(val) {
      console.log(val)
    },
    onSearch() {
      console.log('点击搜索按钮 请求...')
      console.log(JSON.stringify(this.queryParams))
    },
    // lodash文档: https://www.lodashjs.com/
    //
    // 搜索框防抖 - lodash实现
    // 不要在debounce里写箭头函数,否则this的指向就是undefined,而不是Vue实例对象。
    // 注意这里若是使用箭头函数的话, this为 undefined https://github.com/vue-styleguidist/vue-docgen-api/issues/23
    onChange2: lodash.debounce(function() {
      // Do some things
      this.getListByKeyword()
    }, 500),
    getListByKeyword() {
      // 请求...
      console.log('根据关键字 请求...')
      console.log(this.queryParams2.name)
      console.log(JSON.stringify(this.queryParams2))
    },
    // 按钮节流 - lodash实现 - 方式1
    onSearch2: lodash.throttle(function() {
      // Do some things
      this.requestList()
    }, 3000),
    requestList() {
      // 请求...
      console.log('点击搜索按钮 请求...')
      console.log(JSON.stringify(this.queryParams2))
    },
    // 按钮节流 - lodash实现 - 方式2
    onSearch22() {
      // Do some things
      this.requestList3()
    },
    // 防抖
    // 项目工具类
    // 如果需要加参数,则在function空的形参列表里加入
    onChange3: debounce2(function(val) {
      console.log('录入的文字', val)
      // Do some things
      this.getListByKeyword3()
    }, 500),
    getListByKeyword3() {
      // 请求...
      console.log('根据关键字 请求...')
      console.log(this.queryParams3.name)
      console.log(JSON.stringify(this.queryParams3))
    },
    onSearch3: throttle(function() {
      // Do some things
      this.requestList3()
    }, 3000),
    requestList3() {
      // 请求...
      console.log('点击搜索按钮 请求...')
      console.log(JSON.stringify(this.queryParams3))
    }
  }
}
</script>

<style lang="scss" scoped>
::v-deep .el-input__icon:after {
  height: auto;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/331434.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

论文翻译:2022_Phase-Aware Deep Speech Enhancement: It’s All About The Frame Length

摘要 虽然相位感知语音处理近年来受到越来越多的关注&#xff0c;但大多数帧长约为32 ms的窄带STFT方法显示出相位对整体性能的影响相当有限。与此同时&#xff0c;现代基于深度神经网络(DNN)的方法&#xff0c;如Conv-TasNet&#xff0c;隐式修改幅度和相位&#xff0c;在非常…

CUDA虚拟内存管理

CUDA中的虚拟内存管理 文章目录CUDA中的虚拟内存管理1. Introduction2. Query for support3. Allocating Physical Memory3.1. Shareable Memory Allocations3.2. Memory Type3.2.1. Compressible Memory4. Reserving a Virtual Address Range5. Virtual Aliasing Support6. Ma…

自动化测试实战篇(6)jmeter实现脚本录制,抓取接口信息

Jmeter中脚本录制&#xff0c;是一个非常方便找到接口内容的一种工具&#xff0c;不用想fiddler抓包定位接口信息速度不够快 设置代理服务器 这里以谷歌浏览器为例子 打开您的计算机的代理设置 把代理服务器打开这里就以127.0.0.1和8080端口为例子&#xff0c;这个需要记住…

ChatGPT背后的经济账

ChatGPT能否取代Google、百度这样的传统搜索引擎&#xff1f;为什么中国不能很快做出ChatGPT&#xff1f;当前&#xff0c;对这些问题的探讨大多囿于大型语言模型&#xff08;LLM&#xff09;的技术可行性&#xff0c;忽略或者非常粗糙地估计了实现这些目标背后的经济成本&…

((蓝桥杯 刷题全集)【备战(蓝桥杯)算法竞赛-第4天(搜索与图论-下 专题)】( 从头开始重新做题,记录备战竞赛路上的每一道题 )距离蓝桥杯还有63天

&#x1f3c6;&#x1f3c6;&#x1f3c6;&#x1f3c6;&#x1f3c6;&#x1f3c6;&#x1f3c6; 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&a…

差分隐私学习笔记

2021网络空间安全西湖学术论坛线上报告中介绍了差分隐私过去发展&#xff0c;目前现状以及未来研究方向。博主对这个报告进行了介绍与总结。总结中提到学习差分隐私最重要的环节是&#xff1a; 了解差分隐私的基本机制&#xff1a;拉普拉斯机制、指数机制和高斯机制差分隐私的组…

【数据结构与算法】前缀树的实现

&#x1f320;作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《数据结构与算法要啸着学》 &#x1f387;座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;…

54 循环神经网络 RNN【动手学深度学习v2】

54 循环神经网络 RNN【动手学深度学习v2】 深度学习学习笔记 学习视频&#xff1a;https://www.bilibili.com/video/BV1D64y1z7CA/?spm_id_from333.880.my_history.page.click&vd_source75dce036dc8244310435eaf03de4e330 对序列化数据集的训练网络&#xff0c;通常称为RN…

第三章 Opencv图像像素操作

目录1.像素1-1.确定像素位置1-2.获取指定像素的像素值1-3.修改像素的BGR值2.用numpy模块操作像素2-1.创建图像1.创建黑白图像2.创建彩色图像3.创建随机图像2-2.拼接图像1.水平拼接hstack()方法2.垂直拼接vstack()方法1.像素 1.像素是构成数字图像的最小单位。每一幅图像都是由M…

【第29天】SQL进阶-查询优化- performance_schema系列实战四:查看最近的SQL执行信息(SQL 小虚竹)

回城传送–》《32天SQL筑基》 文章目录零、前言一、 查看最近的top sql1.1 数据准备&#xff08;如果已有数据可跳过此操作&#xff09;1.2 查询events_statements_summary_by_digest表二、查看最近执行失败的SQL2.1 开启第一个会话&#xff0c;执行错误sql2.2 开启第二个会话&…

pytest当中pytest.ini使用

目录 一、作用 二、存放位置 三、功能&#xff08;只列了简单的&#xff09; 1、 addopts 2、更改测试用例收集规则 四、运行就减少了命令了 前言&#xff1a;pytest配置文件可以改变pytest的运行方式&#xff0c;它是一个固定的文件pytest.ini文件。 一、作用 pytest.in…

Ceph分部署存储知识总结

Ceph 一.deploy-ceph部署 投入使用ceph前&#xff0c;要知道一个很现实得问题&#xff0c;ceph对低版本内核得客户端使用非常不友好&#xff0c;低内核是指小于等于3.10.0-862&#xff0c;默认的centos7.5及以下的系统都是小于此类内核&#xff0c;无法正常使用ceph的文件存储…

内网渗透(十一)之内网信息收集-内网IP扫描和发现

系列文章第一章节之基础知识篇 内网渗透(一)之基础知识-内网渗透介绍和概述 内网渗透(二)之基础知识-工作组介绍 内网渗透(三)之基础知识-域环境的介绍和优点 内网渗透(四)之基础知识-搭建域环境 内网渗透(五)之基础知识-Active Directory活动目录介绍和使用 内网渗透(六)之基…

用YOLOv8推荐的Roboflow工具来训练自己的数据集

YOLOv8是Ultralytics公司开发的YOLO目标检测和图像分割模型的最新版本&#xff0c;相较于之前的版本&#xff0c;YOLOv8可以更快速有效地识别和定位图像中的物体&#xff0c;以及更准确地分类它们。 作为一种深度学习技术&#xff0c;YOLOv8需要大量的训练数据来实现最佳性能。…

如何旋转YUV图片数据且使用Qt显示

前言 提一下这篇文章的需求&#xff1a;将USB相机获取到的YUV数据进行旋转&#xff0c;然后转为QImage进行显示。原本程序中是有旋转的代码&#xff0c;但不知道为什么&#xff0c;旋转出来的图片会花屏。关于花屏的问题&#xff0c;后面会稍微阐述一下。所以&#xff0c;经过…

[多线程进阶] 常见锁策略

专栏简介: JavaEE从入门到进阶 题目来源: leetcode,牛客,剑指offer. 创作目标: 记录学习JavaEE学习历程 希望在提升自己的同时,帮助他人,,与大家一起共同进步,互相成长. 学历代表过去,能力代表现在,学习能力代表未来! 目录: 1. 常见的锁策略 1.1 乐观锁 vs 悲观锁 1.2 读写…

bootstrap 框架

文章目录bootstrap必须使用 HTML5 文档类型排版和链接默认栅格系统带有基本栅格的 HTML 代码媒体类型媒体类型逻辑运算符 用来做条件判断页面布局&#xff1a; 引入 css&#xff08;bootstrap.min.css&#xff09; 类名03-面包屑导航警告框、徽章、面包屑导航、按钮、按钮组卡…

css行内块元素垂直居中

css行内块元素垂直居中 div里边有个img标签&#xff0c;要想让img垂直居中&#xff0c;需要 给父盒子设置line-heightheightimg设置vertical-align:middle <div style"background-color: red; height: 150px;line-height: 150px;"><img src"images/…

Unity开发环境配置

Unity本体安装 1.首先下载安装unityhub,中文管网https://unity.cn/ 2.登录unityhub&#xff0c;选择你想要的版本安装 选择后按照提示选择个人免费试用的license,然后等待unity本体下载安装即可。 VSCode安装和配置 1.去官网https://code.visualstudio.com/下载vscode 2.u…

微信小程序 Springboot ssm房屋租赁系统uniapp设计与实现

房屋租赁系统用户和户主是基于微信端&#xff0c;管理员是基于网页端&#xff0c;系统采用java编程语言&#xff0c;mysql数据库&#xff0c; idea工具开发&#xff0c;本系统分为用户&#xff0c;户主&#xff0c;管理员三个角色&#xff0c;其中用户可以注册登陆小程序&#…