如果为 True,则反跳 500 毫秒,否则执行

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在任何时候都不会显示

fre*_*n-m 1

尝试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)