代码之家  ›  专栏  ›  技术社区  ›  SoftMemes

用JavaScript过滤客户端项目、从DOM中隐藏或删除的最佳实践?

  •  5
  • SoftMemes  · 技术社区  · 15 年前

    我有一个相对较大的项目数据集(几千个项目),我想通过在Web应用程序中应用一些过滤器客户端来导航这些项目。应用过滤逻辑本身并不是一个问题,问题是使用哪种方法更新匹配结果表以获得最佳用户体验。我想出的方法是:

    1. 将每一行的类设置为隐藏或显示它(使用可见性:折叠以隐藏它),并将dom元素保留在表中。
    2. 为每个数据项保留一个DOM元素,将其分离/附加到表中以隐藏和显示它。
    3. 只需为每个数据项保留一个抽象对象,根据需要创建一个DOM对象来显示它。

    哪一个可能提供最好的用户体验?除了我已经列出的方法,还有其他推荐的方法吗?

    4 回复  |  直到 15 年前
        1
  •  2
  •   Justin Johnson    15 年前

    如果显示区域的大小是固定的(或者至少是最大的),并且您必须在客户端进行筛选,我会 为每个项创建一个DOM节点,但是 将预定义的一组dom节点重用为模板 ,根据筛选器的结果数隐藏不必要的模板。这将大大减少文档中的DOM节点,这些节点将保持页面呈现的响应性,并且非常容易实现。

    示例HTML*:

    <ul id="massive-dataset-list-display">
        <li>
           <div class="field-1"></div>
           <div class="field-2"></div>
           <div class="field-n"></div>
        </li>
        <li>
           <div class="field-1"></div>
           <div class="field-2"></div>
           <div class="field-n"></div>
        </li>
        <li>
           <div class="field-1"></div>
           <div class="field-2"></div>
           <div class="field-n"></div>
        </li>
        .
        .
        .
    </ul>
    

    示例javascript*:

    var MassiveDataset = function(src) {
        var data          = this.fetchDataFromSource(src);
        var templateNodes = $("#massive-dataset-list-display li");
    
        // It seems that you already have this handled, but just for 
        // completeness' sake
        this.filterBy(someParam) {
            var filteredData = [];
            // magic filtering of `data` 
            this.displayResults(filteredData);
        };
    
        this.displayResults(filteredData) {
            var resultCount = filteredData.length;
    
            templateNodes.each(function(index, node) {
                // There are more results than display node templates, start hiding
                if ( index >= resultCount ) {
                    $(node).hide();
                    return;
                }
    
                $(node).show();
                this.formatDisplayResultNode(node, filteredData[i]);
            });
        };
    
        this.formatDisplayResultNode = function(node, rowData) {
            // For great justice
        };
    };
    
    var md = new MassiveDataset("some/data/source");
    md.filterBy("i can haz filter?");
    

    *未经测试。不要期望复制/粘贴可以工作,但这很酷。

        2
  •  1
  •   Ronald    15 年前

    添加类并使用CSS显示/隐藏元素可能是最快的(编码和性能方面),尤其是对于如此多的项。

    如果要执行DOM操作路线,请考虑离线编辑DOM。在内存中缓存DOM树(一个局部变量),更新所有行并替换原始的DOM节点。见 http://www.peachpit.com/articles/article.aspx?p=31567&seqNum=5 关于这件事的更多信息。


    我做过一个项目,需要在谷歌地图的“视区”和最小-最大值滑动条(对于好奇的人来说,这是一个房地产网站)中过滤项目。

    第一个版本使用Ajax请求获取所有(服务器端)筛选的项目,因此过滤器中的每个更改都请求新数据。然后将JSON数据解析为DOM节点并添加到文档中。此外,在这种情况下,搜索引擎无法对项目进行索引。

    第二个版本也使用了Ajax请求,但这次只请求了项目的过滤ID。所有项目都以唯一的ID出现在HTML中,并且筛选的项目有一个额外的类名来最初隐藏它们。每当筛选器更改时,只请求已筛选的ID,并相应地更新项目的类名。这大大提高了速度,特别是在Internet Explorer(它有我们支持的浏览器中最慢的javascript引擎!)…

        3
  •  0
  •   Frank DeRosa    15 年前

    我知道这并不是你想要的,但自从你为替补队员开门后…

    你考虑过在服务器端进行过滤吗?如果用户更改了过滤选项,您可以使用Ajax加载结果,这样,当您可能只显示其中的一部分时,就不会在浏览器中加载数千行数据。虽然这取决于你的网站真正的使用方式,但它可能会节省你和访问者的时间。

    基本上,如果你提前决定要显示什么数据,你就不必费心去挑选那些数据。

    我知道这可能不适合你的需要,但我提供它作为一个建议,以防你被困在客户端的想法。

        4
  •  0
  •   AnthonyWJones    15 年前

    对于“几千个项目”,DOM操作太慢了。假设您有一个真正的、非常好的理由不让服务器进行筛选,那么我发现的最佳解决方案是对保存为XML的数据使用客户端XSL转换。

    即使在相当大的数据集上,转换本身也非常迅速。然后,您将最终将结果分配给要在其中显示表的containing div的innerhtml属性。在DOM中使用innerhtml进行大的更改要比用javascript操作DOM快得多。

    编辑 :对Justin Johnson评论的回答:

    如果数据集这么大,XML可能会非常大。

    注意,我已经在第一段中对服务器的登记做出了免责声明,请在此提供帮助。这里可能存在这样一种情况:转换设计并合理地使用Ajax,或者只是不想一次显示很多数据。不过,我正在尽最大努力回答提出的问题。

    同样值得考虑的是,“非常大”至少是带宽的函数。在一个连接良好的内部网中,Web应用程序的带宽并没有那么高。此外,我还看到并使用了随着时间推移构建和重用缓存XML的实现。

    另外,如果XML被转换为一个DOM对象,这有什么更好的呢?

    我提出的技术和用JavaScript直接操作DOM有很大的不同。考虑一下,当javascript中的代码修改DOM时,底层引擎无法知道其他更改即将发生,也无法确保javascript不会立即检查DOM的其他属性。因此,当JavaScript对DOM进行更改时,浏览器需要确保它更新所有其他属性,以便它们与完成的呈现一致。

    但是,当innerhtml被分配一个大的html字符串时,浏览器可以很高兴地创建一整串的dom对象,而不需要进行任何重新计算,它可以将无数次更新推迟到不同的属性值,直到整个dom被构造完为止。因此,对于大规模的更改,innerhtml会将直接DOM操作吹出水面。