由于微信小程序与普通网页的开发、编译、运行机制都有所不同,在防抖节流的方法使用上也就需要我们做一些比较棘手的适配操作。常见的H5开发的防抖节流此处就不再分享了,网上有太多的教程,或者直接问那群AI即可。
OK,言归正传,直接上代码:
一、防抖函数(TS版)及其使用案例
1、文件:pages/utils/index.ts
ts
/**
* 防抖函数 debounce
*
* @param fn 要防抖的函数
* @param wait 等待时间,默认为500毫秒
* @param isImmediate 是否立即执行,默认为true
* @returns 返回防抖处理后的函数
*/
let timerId: number | null = null;
let flag = true;
export const debounce = (fn: { apply: (arg0: any, arg1: IArguments) => void; }, wait = 500, isImmediate = true) => {
if (isImmediate) {
return function () {
// @ts-ignore
const context = this;
timerId && clearTimeout(timerId);
if (flag) {
fn.apply(context, arguments);
flag = false;
}
timerId = setTimeout(() => {
flag = true;
}, wait);
};
}
return function () {
// @ts-ignore 将当前上下文(this)赋值给 context
const context = this;
timerId && clearTimeout(timerId);
timerId = setTimeout(() => {
fn.apply(context, arguments);
}, wait);
};
};
2、文件:pages/views/demoPage/index.ts
ts
import { debounce } from '../../utils/index';
Page({
/** 实际需要执行的方法 */
clickHandler(e: any) {
console.log('[clickHandler] e.currentTarget.dataset >>>');
console.log(e.currentTarget.dataset);
},
/**
* 防抖处理后的方法
* 说明一下:其实这个才是重点,debounce写完以后,怎么绑定到页面中是个大问题!
* 再尝试多次后,得出以下正确使用方式!
* 当然,如果有更好的写法,欢迎大家评论补充,感谢一起分享!
*/
dbClickHandler(e) {
debounce(this.clickHandler)(e);
},
});
3、文件:pages/views/demoPage/index.wxml
这个就正常的bind就行,需要稍微注意的就是要bind包裹了一层防抖函数的 dbClickHandler
,如下:
html
<button data-key="demoKey" bind:tap="dbClickHandler"></button>
二、节流函数(TS版)及其使用案例
节流的场景相对防抖还是比较少的,但是例如搜索框的大舌头效果还是很经典的,这个搜索提示的场景要求我们在节流的同时,必须确保用户最后一次输入的值执行搜索函数,因此该方法还是有那么点麻烦。
1、文件:pages/utils/index.ts
ts
// 定义一个泛型类型 Func,代表任何接收任意参数并返回任意结果的函数
type Func = (...args: any[]) => any;
/**
* 节流函数,用于限制给定函数的执行频率。
*
* @param fn 需要进行节流的函数。
* @param delay 函数执行之间的延迟时间,以毫秒为单位。默认为500毫秒。
* @returns 返回一个新函数,当调用该新函数时,会根据指定的延迟时间执行被节流的函数。
*/
export function throttle(fn: Func, delay = 500) {
let lastFunc: any;
let lastRan: number;
let context: any;
let args: any;
let result: any;
// 定义一个内部函数 executeFunc,用于实际执行传入的函数 fn
const executeFunc = function () {
result = fn.apply(context, args);
lastRan = Date.now();
clearTimeout(lastFunc as any);
lastFunc = null;
context = null;
args = null;
};
// 返回一个新的函数,该函数在被调用时会执行节流逻辑
return function () {
// @ts-ignore 将当前上下文(this)赋值给 self
const self = this;
context = self;
args = arguments;
const now = Date.now();
if (!lastRan) {
executeFunc();
lastRan = now;
} else if (now - lastRan < delay) {
if (lastFunc) {
clearTimeout(lastFunc as any);
}
lastFunc = setTimeout(executeFunc, delay);
} else {
executeFunc();
}
return result;
};
}
2、文件:pages/views/demoPage/index.ts
ts
import { throttle } from '../../utils/index';
Page({
/** 实际需要执行的方法 */
myInputChange(e: any) {
console.log('[myInputChange] doing...');
console.log('[myInputChange] id:', e.target.id);
console.log('[myInputChange] value:', e.detail.value);
},
/**
* 节流处理后的方法
* 注意:为了能成功用上节流这个方法,此处的写法也必须是这样类似选项式的写法
*/
throttleInputChange: throttle(function(e) {
console.log('[throttleInputChange] doing...');
// @ts-ignore
this.myInputChange(e)
}),
});
3、文件:pages/views/demoPage/index.wxml
以下是一个地址搜索框的例子,还是注意下bind包裹后的节流函数throttleInputChange
即可。
html
<input id='address' placeholder="小区/写字楼/学校等" bindinput="throttleInputChange" />
END.