1

我有一个搜索框,可以隐藏列表中不包含输入文本的所有行。

在列表长到 10,000 行之前,这很有效。一次击键很好,但如果用户键入几个字母的单词,则每次按键都会迭代该函数。

如果按下新键,我想要做的是放弃以前执行的功能。

函数很简单,如下:

    $("#search").keyup(function(e) {
       goSearch();
    });

function goSearch()
{
var searchString = $("#search").val().toLowerCase();
$(".lplist").each(function(index, element) {
    var row = "#row-" + element.id.substr(5);
        if ($(element).text().toLowerCase().indexOf(searchString,0) != -1)
    $(row).show();
    else
    $(row).hide();
});
}

谢谢

4

3 回答 3

0

您可以使用全局变量来保存搜索字符串并在搜索字符串更改时停止执行。

重要提示:您必须在每次迭代中设置超时,以便暂停函数执行并更新全局变量,因为 JavaScript 是单线程的。

您的代码如下所示:

var searchString;

$("#search").keyup(function(e) {
    // Update search string
    searchString = $("#search").val().toLowerCase();

    // Get items to be searched
    var items = $(".lplist");

    // Start searching!
    goSearch(items, searchString, 0);
});

function goSearch(items, filter, iterator)
{
    // Exit if search changed
    if (searchString != filter) {
        return;
    }

    // Exit if there are no items left
    if (iterator >= items.length) {
        return;
    }

    // Main logic goes here
    var element = items[iterator];
    var row = "#row-" + element.id.substr(5);
    if ($(element).text().toLowerCase().indexOf(filter, 0) != -1)
        $(row).show();
    else
        $(row).hide();

    // Schedule next iteration in 5 ms (tune time for better performance)
    setTimeout(function() {
        goSearch(items, filter, iterator + 1);
    }, 5);
}
于 2013-03-12T09:19:49.120 回答
0

你不能直接。Javascript 不是多线程的,因此您的函数将运行并阻止任何按键,直到它完成。

从用户体验的角度来看,可以容忍的方式是不要在关键事件上立即触发函数,而是等待一小段时间然后触发事件。

当用户打字时,超时函数会不断地设置和重置,因此不会调用 gosearch 函数,因此用户的打字不会被打断。

当用户暂停输入时,超时将倒计时至零并调用搜索功能,该功能将运行并阻止输入直到完成。但这没关系(只要它在一秒钟左右完成),因为用户当前可能没有尝试输入。

您还可以通过将 gosearch 函数分解为块来执行您实际要求的操作,其中每次调用该函数: * 读取到目前为止已处理的行数的计数器,然后再处理 500 行并增加计数器。* 使用 setTimeout 调用另一个 gosearch,时间值为零。这会向其他“线程”产生事件,并允许快速更改搜索项。

var goSearchTimeout = null;
var linesSearched = 0;

function keySearch(e){
    if(goSearchTimeout != null){
        clearTimeout(goSearchTimeout);
        linesSearched = 0;
    }
    goSearchTimeout = setTimeout(goSearch, 500);
}

$("#search").keyup(keySearch);

function highLight(index, element) {

    if(index >= linesSearched){
        var row = "#row-" + element.id.substr(5);
        if ($(element).text().toLowerCase().indexOf(searchString,0) != -1){
        $(row).show();
    else{
        $(row).hide();
    }
    if(index > linesSearched + 500){
        linesSearched = index;
        goSearchTimeout = setTimeout(goSearch);
        return;
    }
}

function goSearch(){
    goSearchTimeout = null;
    var searchString = $("#search").val().toLowerCase();
    $(".lplist").each(highLight);
}

如果您要使用这样的超时回调,我强烈建议您将代码包装到 jQuery 小部件中,以便您可以使用对象上的变量来存储变量 goSearchTimeout 等,而不是让它们作为全局变量浮动。

于 2013-03-12T08:48:20.023 回答
0

引入一个var keypressCount由您的按键事件处理程序增加的计数器。在开始goSearch()将其值写入缓冲区。然后在每次运行时$(".lplist").each()询问电流keypressCount是否与缓冲的相同;如果没有,你就回来。我建议你使用 afor()虽然 ,因为它break;$.each().

更新:您必须确保有时间触发/接收新的按键事件,因此将 $.each() 的匿名函数包装在超时内。

参考:http ://www.garrickcheung.com/javascript/what-i-learned-about-multi-threading-in-javascript/

于 2013-03-12T08:34:02.107 回答