jQuery 只执行最后一个事件

jQuery execute only the last event

刚果提出 1000 万个问题!

我有一个 table 行数 > 200。 我在 table 行中搜索特定文本,如果文本存在(作为行中的子字符串),我将遍历这些行并使它们可见。如果文本不存在,我会让它们不可见。我在文本字段上使用输入侦听器来检测键入的文本:

$(document).ready(function () { //bind when DOM ready
    $('[name="token_search"]').on("input", function (evt) { //listener on textfield
        if ($(this).val() == "") { //if no text-show all rows
            $(".tokens-table tr").show();
            return;
        } else { //filter rows based on typed text
            $(".tokens-table tr").each(function (index) {
                if (index > 1) //do not hide first two rows
                    if ($(this).children()[0].innerHTML.indexOf($('[name="token_search"]').val()) != -1) {
                        $(this).show();
                    } else {
                        $(this).hide();
                    }
            });
        }
    });
});

当用户键入文本时,该方法将对超过 200 个项目的每个输入事件进行子字符串搜索。当用户打字速度太快或在低端设备上打字时,这会导致 UI 挂起。如何修改上述代码以仅对搜索字段中的最后一个输入事件执行而不是对队列中的所有输入事件执行?我的意思是,只要用户键入一个新字符,我就希望队列中的所有先前事件都被清除。

基本上,您需要使用计时器来等待用户停止输入一段设定的时间,然后调用您的函数。正如 charlietfl 指出的那样,只要您要在代码中多次使用它们,您还应该缓存元素和值。以下应该可以解决问题。:

不过,老实说,如果您打算创建一个搜索框来过滤 table,您可能需要研究一下 DataTables,它在过滤方面做得非常出色等等.

 $(document).ready(function() { //bind when DOM ready
   $('[name="token_search"]').on("keyup", function(evt) { //listener on textfield
     var $this = $(this);
     var value = $this.val(); // incorporated charlietfl's improvements
     // cache the value of the search input and this
     delay(function() {
       $(".tokens-table tr:gt(1)").each(function(index, element) {
         var $element = $(element);
         $this.val() == "" || $element.children()[0].innerHTML.indexOf(value) != -1 ? $element.show() : $element.hide();
       });
     }, 700); // waits till the user has stopped typing for 7/10 of a second, adjust as needed
     // 1000 = 1 second
   });
 });

 var delay = (function() {
   var timer = 0;
   return function(callback, ms) {
     clearTimeout(timer);
     timer = setTimeout(callback, ms);
   };
 })();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" name="token_search" id=""><br><br>
    
    <table class="tokens-table">
        <tr>
            <td>unfilterable row</td>
            <td>some data</td>
            <td>some data</td>
        </tr>
        <tr>
            <td>unfilterable row</td>
            <td>some data</td>
            <td>some data</td>
        </tr>
        <tr>
            <td>one</td>
            <td>some data</td>
            <td>some data</td>
        </tr>
        <tr>
            <td>two</td>
            <td>some data</td>
            <td>some data</td>
        </tr>
        <tr>
            <td>one</td>
            <td>some data</td>
            <td>some data</td>
        </tr>
        <tr>
            <td>four</td>
            <td>some data</td>
            <td>some data</td>
        </tr>
        <tr>
            <td>one</td>
            <td>some data</td>
            <td>some data</td>
        </tr>
        <tr>
            <td>three</td>
            <td>some data</td>
            <td>some data</td>
        </tr>
        <tr>
            <td>two</td>
            <td>some data</td>
            <td>some data</td>
        </tr>
        <tr>
            <td>one</td>
            <td>some data</td>
            <td>some data</td>
        </tr>
        <tr>
            <td>three</td>
            <td>some data</td>
            <td>some data</td>
        </tr>
        <tr>
            <td>one</td>
            <td>some data</td>
            <td>some data</td>
        </tr>
    </table>
    

代码中一个非常昂贵的部分是在每次迭代中搜索 dom 以获取事件处理程序本身内部已有的 input 的值。

对值和 jQuery 对象进行一些缓存。

这个片段是最昂贵的片段:

 .... indexOf($('[name="token_search"]').val())

相反:

 $('[name="token_search"]').on("keyup", function (evt) { 
      var  value = this.value;
      if (value)...
       ....

          .... indexOf(value)

这将删除您对相同值的 DOM 100 次搜索

同样,如果您对同一个 this 使用 $(this) 多次,请将其缓存为变量

$(".tokens-table tr").each(function (index) {
     var $this = $(this);
     if ($this.children()[0].innerHTML.indexOf(value) != -1) {
        $this.show();
     }
});

如果这些改进没有帮助,那么您还可以实施显示的其他解决方案,例如 throttlingdebouncing 使用计时器的搜索间隔时间