• Vue3如何实现防抖动功能?
  • 发布于 1周前
  • 128 热度
    0 评论
今天 在做输入查询优化的时候,想到了js防抖操作,记录一下,以便下次使用。防抖的名词解释:在一段时间内,不论触发多少期回调,都以最后一次为准。稍微想一下,就可以明白,其中用到了定时器。

先来一个原生js 版本的防抖操作:
 module.exports.debounce = (fn, delay) => {
    let timer;
    return (...args) => {
      // 堆代码 duidaima.com
      // 判断定时器是否存在,清除定时器
      if (timer) {
        clearTimeout(timer);
      }
  
      // 重新调用setTimeout
      timer = setTimeout(() => {
        fn.apply(this, args);
      }, delay);
    };
  };
测试:
const { debounce } = require("./debounce.js");
let i = 1;
function fn(params) {
    console.log(`打印次数${i++}次;params=${params}`);
}
const fn2 = debounce(fn,100);
fn2(1);
fn2(2);
setTimeout(() => {
    fn2(4);
}, 50);

setTimeout(() => {
    fn2(5);
}, 1500);
结果:

一共打印了两次,按名词解释,其结果就是我们想要的。下面我们在真实的场景中,使用一下(uniapp中(vue2的语法))
<input class="input" :class="{ center: !active && mode === 2 }"
@input="handleKeywordInput" />
 /* 堆代码 duidaima.com */  
/* 输入事件 */
    handleKeywordInput(e) {
    /* 防抖函数(以最后一次为准) */
    if (this.timeoutID) {
        clearTimeout(this.timeoutID);
    }
    // 重新调用setTimeout
    this.timeoutID = setTimeout(() => {
        let keyword = e.detail.value;
        /* 通知加载相似数据 */
        if (keyword !== '') {
            this.showSearchList = true;
            this.$emit('handleKeywordInput', keyword);
        } else {
            this.showSearchList = false;
        }
    }, 500);
},
看代码我们发现,其实现的过程跟原生js的有些不同,原生js可通过闭包的方式,获取到上一次的定时器的id(没有就请求,有就删除定时器id,重新计时),而这里却没有使用闭包,是使用了timeoutID 这个全局变量来保存上一次的定时器id,为啥呢?原因就是,在vue2中我们没有办法实现,数据和方法是分开定义的,而闭包返回的是一个函数,在此处没办法定义与使用的,这也就不能抽出一个公共方法来了。

然而在vue3中,我们却可以使用Composition API来实现。我们来看一下代码:
function handleDebounce(fn, delay) {
  let timer;
  return (...args) => {
    // 判断定时器是否存在,清除定时器
    if (timer) {
      clearTimeout(timer);
    }

    // 重新调用setTimeout
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
};

export default {
  handleDebounce
}
<template>
  <!-- <h1>{{ msg }}</h1> -->
  <h2>修改次数:{{ countRef }}</h2>
  <!-- <button @click="handleAddCount">count is: {{ countRef }}</button> -->
  <input type="text" v-model="keyName" @input="debounceFn" />
</template>

<script>
import { ref } from "vue";
import common from "../utils/common.js";
export default {
  name: "HelloWorld",
  props: {
    msg: String,
  },
  setup() {
    const { handleDebounce } = common;
    let countRef = ref(0);
    let keyName = ref("");
    let i = 0;
    let debounceFn = handleDebounce(handleAddCount, 500);

    function handleAddCount(params) {
      console.log(`执行了${++i}次`);
      countRef.value++;
    }
    return { countRef, handleAddCount, keyName, debounceFn };
  },
};
</script>
在setup函数中 ,不管是代理对象,还是函数,都可以定义在一起,需要的使用的时候,只需要return 出去使用即可,这样的写法,就和原生js没有什么差别了。看完代码,我们也可以体会到vue3是更加贴近原生js的写法,这样的写法,减少了框架的约束,虽然vue3也是框架,但其约束比vue2小多了。
用户评论