今天 在做输入查询优化的时候,想到了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小多了。