使用 JavaScript 在记录列表中快速过滤

Fast filter in a list of records with JavaScript

我在网页上有一个包含大约 10 000 个客户的列表,需要能够在此列表中搜索匹配的输入。它有一些延迟,我正在寻找提高性能的方法。这是我使用的 HTML 和 JavaScript 的简化示例:

<input id="filter" type="text" />
<input id="search" type="button" value="Search" />
<div id="customers">
    <div class='customer-wrapper'>
        <div class='customer-info'>
            ...
        </div>
    </div>
    ...
</div>

<script type="text/javascript">
    $(document).ready(function() {
        $("#search").on("click", function() {
            var filter = $("#filter").val().trim().toLowerCase();
            FilterCustomers(filter);
        });
    });

    function FilterCustomers(filter) {
        if (filter == "") {
            $(".customer-wrapper").show();
            return;
        }
        $(".customer-info").each(function() {
            if ($(this).html().toLowerCase().indexOf(filter) >= 0) {
                $(this).parent().show();
            } else {
                $(this).parent().hide();
            }
        });
    }
</script>

问题是,当我点击“搜索”按钮时,有很长的延迟,直到我得到包含匹配结果的列表。有没有更好的方法来过滤列表?

问题是你正在迭代记录,如果有 10000 条记录,它可能会很慢,所以我的建议是稍微改变结构,这样你就不必迭代了:

  1. customer-wrapper 上定义列表的所有 css 特征 class 并使其成为所有列表元素的 父级 div.

  2. 当您的 ajax 请求添加一个元素时,创建一个包含名称的变量来替换下划线的空格,我们称之为 underscore_name.

  3. 将名称添加到列表中:

var customerHtml = "<div id='"+underscore_name+'>" + name + "</div>";

列表中的每个元素都有一个与名称"almost"相同的唯一 ID,并且列表中的所有元素都在 同一级别customer-wrapper class.

  1. 对于搜索,您可以将用户输入的空格替换为下划线并放入变量中,例如 searchable_id,然后使用 Jquery:

$('#'+searchable_id).siblings().hide();

siblings 将隐藏与 searchable_id.

同一级别的其他元素

它可能遇到的唯一问题是出现两个或更多重复名称的情况,因为它会尝试创建两个或更多具有相同 ID 的 div。

您可以在 http://jsfiddle.net/mqpsppxm/ 上查看一个简单的实现

感谢您的所有回答和评论,我至少得到了令人满意的性能结果的解决方案。我已经清理了多余的包装器并将列表中的元素 showing/hiding 分组,而不是对每个元素单独进行。下面是过滤现在的样子:

function FilterCustomers(filter) {
    if (filter == "") {
        $(".customer-info").show();
    } else {
        $(".customer-info").hide();
        $(".customer-info").removeClass("visible");
        $(".customer-info").each(function() {
            if ($(this).html().toLowerCase().indexOf(filter) >= 0) {
                $(this).addClass("visible");
            }
        });
        $(".customer-info.visible").show();
    }
}

和一个测试示例http://jsfiddle.net/vtds899r/

1) DOM 操作通常很慢,尤其是当您追加新元素时。将所有 html 放入一个变量中并附加它,这会导致一个 DOM 操作并且比对每个元素

快得多
function LoadCustomers() {
    var count = 10000;
    var customerHtml = "";
    for (var i = 0; i < count; i++) {
        var name = GetRandomName() + " " + GetRandomName();
        customerHtml += "<div class='customer-info'>" + name + "</div>";
    }
    $("#customers").append(customerHtml);
}

2) jQuery.each() 很慢,请改用 for 循环

function FilterCustomers(filter) {
    var customers = $('.customer-info').get();
    var length = customers.length;
    var customer = null;
    var i = 0;
    var applyFilter = false;
    if (filter.length > 0) {
        applyFilter = true;
    }
    for (i; i < length; i++) {
        customer = customers[i];
        if (applyFilter && customer.innerHTML.toLowerCase().indexOf(filter) < 0) {
            $(customer).addClass('hidden');
        } else {
            $(customer).removeClass('hidden');
        }
    }
}

示例:http://jsfiddle.net/29ubpjgk/