Cut*_*son 5 javascript jquery debouncing
剧透;我对 jQuery/Javascript 完全陌生。
我有一个布尔字段CheckMe和一个输入字段textField。
如果textField为空,则CheckMe不应显示,否则应该显示(这意味着如果从非空变为空,CheckMe则应立即再次隐藏)。我想解析一个延迟,比如说 500 毫秒,即CheckMe显示如果text如果不为空并且在最后一次按键 500 毫秒后
我尝试使用此SO 答案中的去抖函数(请参阅下面的实现),但问题是,在空CheckMe500 毫秒后也首先隐藏textField
<script type="text/javascript">
function debounce(fn, duration) {
var timer;
return function(){
clearTimeout(timer);
timer = setTimeout(fn, duration);
}
}
$(document).ready(function () {
const textField= $("#textField");
const CheckMe= $("#CheckMe");
CheckMe.hide();
textField.on("input", debounce(()=> {
if (textField.val()) {
CheckMe.show();
} else {
CheckMe.hide();
}
},500));
});
</script>
Run Code Online (Sandbox Code Playgroud)
但当checkMe我清除时,它会在 500 毫秒后消失textField它就会消失。
我尝试将 debounce 移至 True 语句中,即
...
textField.on("input", function() {
if (textField.val()) {
debounce(function(){CheckMe.show();},500)
} else {
CheckMe.hide();
}
}
Run Code Online (Sandbox Code Playgroud)
但这CheckMe在任何时候都不会显示
尝试if () { debouce(()={}); } else { immediate(); }不起作用的原因是事件处理程序如何存储函数以及 debounce 如何存储其计时器。
当您运行.on("input", function() { }) 时,该函数定义存储在事件处理程序中,准备运行。然而,对于 debounce,这并不是正在做的事情,而是:
.on("input", function())
Run Code Online (Sandbox Code Playgroud)
没有函数定义- 它调用函数本身,该函数恰好返回事件运行时要调用的另一个函数。
这就是为什么有这么多的问题,比如“我的代码在我.on("input", myfunction())应该执行的时候立即运行”.on("input", myfunction)
因此,一个函数(去抖)在每次事件设置时运行一次- 不是每次input事件触发一次,而是在设置事件时运行一次。因此,只有一个实例,var timer并且它全部包含在 debounce 函数中。return function()然后,事件触发调用先前已在其外部范围中定义的代码var timer(之前的去抖调用)。
如果您使用第二个输入再次调用 debounce,$("#secondInp").on("input", debounce(() => ...您将获得该函数的第二个实例及其自己的变量(因此它们在 inp1 和 inp2 之间不会发生冲突)。
因此,您可以看到,如果将其放入事件处理程序中(在 中),则每次if都会调用一个新的去抖(不是同一个)。
您的尝试没有执行任何操作,因为您的代码debounce(function(){CheckMe.show();},500)只是返回该函数 - 所以您需要这样做
debounce(function(){CheckMe.show();},500)();`
Run Code Online (Sandbox Code Playgroud)
但即使这样也不起作用,因为每次调用它(每个事件)时,您都会获得 debounce 函数的新实例和var timer.
您可以使用两个事件。在每个事件中检查是否应显示“检查我”。
ddebounce会在 500ms 后运行,未去抖的会立即运行。
.on("input", function())
Run Code Online (Sandbox Code Playgroud)
debounce(function(){CheckMe.show();},500)();`
Run Code Online (Sandbox Code Playgroud)
function debounce(fn, duration) {
var timer;
return function() {
clearTimeout(timer);
timer = setTimeout(fn, duration);
}
}
$(document).ready(function() {
const textField = $("#textField");
const checkMe = $("#checkMe");
checkMe.hide();
textField.on("input", debounce(() => {
if (textField.val()) {
checkMe.show();
}
}, 500));
textField.on("input", () => {
if (!textField.val()) {
checkMe.hide();
}
});
});Run Code Online (Sandbox Code Playgroud)
是否可以将其保留在单个 if-else 中
鉴于上面的解释,不可能按debounce原样使用您的函数;因为return function() { }和 的单个实例timer。关键是 的单个实例timer。
如果没有去抖,这可以在单个函数中实现,使用计时器的外部变量,但每次都需要重复去抖代码(例如,对于第二个输入) - 只是clearTimeout和setTimeout代码 - 所以不多 - 它是“全局”/外部范围变量成为一个问题。
#checkMe { color: red; }Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="textField" type="text">
<div id='checkMe'>^-- check this</div>Run Code Online (Sandbox Code Playgroud)
$(document).ready(function() {
var textFieldTimer = null;
const textField = $("#textField");
const checkMe = $("#checkMe");
checkMe.hide();
textField.on("input", () => {
if (textField.val()) {
clearTimeout(textFieldTimer);
textFieldTimer = setTimeout(() => checkMe.show(), 500);
}
else {
checkMe.hide();
}
});
});Run Code Online (Sandbox Code Playgroud)
那么我们如何才能同时使用:可重用函数和if事件处理程序内部呢?
通过在元素本身上存储的单个实例timer.data()-在下面的代码中使用,但任何为每个元素存储单个实例的方法也将起作用。
下面是一个示例,使用带有 和 的单个事件if来重复第二个输入,以显示它的工作原理。
#checkMe { color: red; }Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="textField" type="text">
<div id='checkMe'>^-- check this</div>Run Code Online (Sandbox Code Playgroud)
function debounce2(fn, duration)
{
var timer = $(this).data("timer");
clearTimeout(timer);
$(this).data("timer", setTimeout(fn, duration));
}
$(document).ready(function() {
$("#checkMe, #checkMe2").hide();
$("#textField, #textField2").on("input", function() {
if ($(this).val()) {
debounce2.call(textField, () => $("#checkMe").show(), 500);
}
else {
$("#checkMe").hide();
}
});
// second input confirming `timer` is per element.
$("#textField2").on("input", function() {
if ($(this).val()) {
debounce2.call(textField, () => $("#checkMe2").show(), 500);
}
else {
$("#checkMe2").hide();
}
});
});Run Code Online (Sandbox Code Playgroud)