使用JavaScript快速筛选记录列表

使用JavaScript快速筛选记录列表,javascript,jquery,html,dom,Javascript,Jquery,Html,Dom,我在一个网页上有一个大约10000名客户的列表,需要能够在此列表中搜索匹配的输入。它会有一些延迟,我正在寻找提高性能的方法。下面是我使用的HTML和JavaScript的简化示例: <input id="filter" type="text" /> <input id="search" type="button" value="Search" /> <div id="customers"> <div class='customer-wrapper

我在一个网页上有一个大约10000名客户的列表,需要能够在此列表中搜索匹配的输入。它会有一些延迟,我正在寻找提高性能的方法。下面是我使用的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>

...
...
$(文档).ready(函数(){
$(“#搜索”)。在(“单击”,函数()上){
var filter=$(“#filter”).val().trim().toLowerCase();
过滤器客户(过滤器);
});
});
功能过滤器客户(过滤器){
如果(过滤器==“”){
$(“.customer wrapper”).show();
返回;
}
$(“.customer info”)。每个(函数(){
if($(this.html().toLowerCase().indexOf(filter)>=0){
$(this.parent().show();
}否则{
$(this.parent().hide();
}
});
}

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

问题是,您正在迭代记录,拥有10000条记录可能会非常慢,因此我的建议是稍微更改结构,这样您就不必迭代:

  • customer wrapper
    并使其成为所有列表元素的父div

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

  • 将名称添加到列表中,如下所示:

  • var customerHtml=“+name+”

    列表中的每个元素都有一个唯一的id,该id将与名称“几乎”相同,并且列表中的所有元素都将位于
    customer wrapper
    类下的同一级别

  • 对于搜索,您可以使用用户输入替换下划线的空格,并将其放入变量中,例如
    searchable\u id
    ,并使用Jquery:
  • $(“#”+可搜索的_id).兄弟姐妹().hide()

    同级
    将隐藏与可搜索\u id相同级别上的其他元素

    它可能存在的唯一问题是,如果出现两个或多个重复名称的情况,因为它将尝试创建两个或多个具有相同id的div

    您可以在上检查一个简单的实现

    多亏了您的回答和评论,我至少找到了性能令人满意的解决方案。我已经清理了多余的包装,并在列表中分组显示/隐藏元素,而不是对每个元素单独进行。下面是过滤现在的样子:

    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();
        }
    }
    
    一个测试示例

    1)DOM操作通常很慢,尤其是在添加新元素时。将所有html放入一个变量并附加它,这将导致一个DOM操作,并且比为每个元素执行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);
    }
    

    示例:

    我建议您将此问题转移到
    GetRandomName
    之外的
    LoadCustomers()
    中,并且只进行一次循环调用(更改返回以满足您的需要)将有所改进。。。ut codereview是您的位置!谢谢你们的评论,我以前不知道代码审查。我从问题中删除了LoadCustomers()的测试示例,因为根本不存在问题。列表更新缓慢,这就是FilterCustomers(filter)功能。瓶颈是那些
    .show()
    .hide()
    东西。从循环中删除它们:收集迭代中的项目,并将它们放入两个bucket/列表中,一旦完成
    show
    show
    bucket中的项目,然后
    hide
    其余的项目。为什么您一次需要在DOM中输入10000个名称?这是用户的信息过载,渲染速度慢。改为过滤数据,然后更新DOM谢谢您的建议!首先,消除要过滤的对象周围的冗余HTML非常好。其他的则不适合,因为过滤器应该适用于许多匹配项。此外,为对象提供客户名称是个坏主意,因为它们包含许多Unicode符号(它们不全是英语),但是客户有数字ID,如果有帮助的话,可以使用数字ID。
    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');
            }
        }
    }