【问题标题】:Debounce for 500ms if True else execute如果为真则反跳 500 毫秒,否则执行
【发布时间】:2021-07-02 00:25:56
【问题描述】:

剧透;我对 jQuery/Javascript 完全陌生。

我有一个布尔字段 CheckMe 和一个输入字段 textField

如果textField 为空,则不应显示CheckMe,否则应显示(这意味着如果从非空变为空CheckMe 应立即再次隐藏)。我想解析一个延迟,比如 500 毫秒,即如果 text 不为空并且在最后一次按键 500 毫秒后显示 CheckMe

我曾尝试使用this SO 答案中的 debounce 功能(请参阅下面的实现),但问题是,CheckMetextField 为空 500 毫秒后也首先隐藏

<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>

但是当我清除 textField 时,它会在 500 毫秒后删除 checkMe

我已经尝试将 debounce 移到 True 语句中,即

...
   textField.on("input", function() {
      if (textField.val()) {
        debounce(function(){CheckMe.show();},500)
      
      } else {

        CheckMe.hide();
      }
}

但在任何时候都不会显示CheckMe

【问题讨论】:

  • 请澄清:您希望它在有人停止输入后出现 500 毫秒。但是您希望它立即消失(只要输入清晰,但不是在 500 毫秒后)?
  • 正确 - 当用户停止输入 500 毫秒后出现,但在第二个 textField 为空时消失,即呼叫 CheckMe.hide() 不应延迟,但 CheckMe.show() 应延迟 500 毫秒后用户停止输入
  • 您可能需要包含一些 HTML/sn-p。 priceThresholdtextField 之间有什么关系 - 它们是否相同,只是问题中的一个错字?
  • 只是一个错字——我已经编辑过了

标签: javascript jquery debounce


【解决方案1】:

if () { debouce(()={}); } else { immediate(); } 的尝试不起作用的原因是事件处理程序如何存储函数以及 debounce 如何存储其计时器。

当您运行.on("input", function() { }) 时,该函数定义存储在事件处理程序中,准备运行。然而,对于去抖动,这不是正在做的事情,而是:

.on("input", function())

没有函数定义 - 它调用函数本身,当事件运行时恰好返回另一个要调用的函数。

这就是为什么有这么多关于 SO 的问题,比如“我的代码在我执行 .on("input", myfunction()) 时会立即运行,而应该是 .on("input", myfunction)

因此,一个函数(去抖动)在每个事件设置中运行一次 - 不是在每个 input 事件触发时运行一次,而是在设置事件时运行一次。所以只有一个 var timer 实例,它都包含在 debounce 函数中。然后事件触发调用 return function() 内的代码,该代码已经在其外部范围内定义了 var timer(之前的去抖调用)。

如果您使用第二个输入 $("#secondInp").on("input", debounce(() =&gt; ... 再次调用 debounce,您将获得具有自己变量的函数的第二个实例(因此它们不会在 inp1 和 inp2 之间发生冲突)。

所以你可以看到,如果你把它放在事件处理程序中(在if 中),你每次都会调用 new debounce(不是同一个)。

您的尝试什么也没做,因为您的代码 debounce(function(){CheckMe.show();},500) 只是返回函数 - 所以您需要这样做

debounce(function(){CheckMe.show();},500)();`

但即使这样也不会起作用,因为每次它被调用(每个事件)你会得到一个 debounce 函数的新实例和一个 var timer 的新实例。


您可以使用两个事件。在每个事件中检查是否应该显示“检查我”。

debounced 将在 500 毫秒后运行,未去抖动的将立即运行。

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();
    }
  });
});
#checkMe { color: red; }
<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>

是否可以将其保存在单个 if-else 中

鉴于上述解释,您无法按原样使用您的debounce 函数;因为return function() { }timer 的单个实例。关键是timer的单个实例

如果没有去抖,这可以在单个函数中实现,使用一个 outer 变量作为计时器,但每次都需要重复去抖代码(例如,对于第二个输入) - 只是clearTimeout 和 setTimeout 代码 - 不多 - 成为问题的是“全局”/外部范围变量。

$(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();
    }
  });
});
#checkMe { color: red; }
<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>

那么我们如何同时使用:可重用函数和事件处理程序内部的if

通过在元素本身上存储 timer 的单个实例 - 在下面的代码中使用 .data(),但任何为每个元素存储单个实例的方法也可以工作。

这是一个示例,使用带有 if 的单个事件并重复第二个输入以显示其工作原理。

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();
    }
  });  
});
#checkMe, #checkMe2 { color: red; }
<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>
<hr/>
<input id="textField2" type="text">
<div id='checkMe2'>^-- check this</div>

【讨论】:

  • 啊,是的 - 这行得通!但是是否可以将其保留在 if-else 中?只是为了让它更具可读性
  • return function() 和事件处理程序不是这样工作的。我会添加一些细节..
猜你喜欢
  • 2021-02-10
  • 1970-01-01
  • 2014-10-17
  • 1970-01-01
  • 2014-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多