使用 JavaScript 在客户端过滤项目、隐藏或从 DOM 中删除的最佳实践?
Posted
技术标签:
【中文标题】使用 JavaScript 在客户端过滤项目、隐藏或从 DOM 中删除的最佳实践?【英文标题】:Best practice for filtering items client-side with JavaScript, hide or remove from DOM? 【发布时间】:2010-12-14 10:55:31 【问题描述】:我有一个相对较大的项目数据集(几千个项目),我想通过在 Web 应用程序中应用多个过滤器客户端进行导航。应用过滤逻辑本身不是问题,问题是使用哪种方法来更新匹配结果表以获得最佳用户体验。我想出的方法是:
-
设置每一行的类隐藏或显示(使用可见性:折叠隐藏它),并将 DOM 元素保留在表格中。
为每个数据项保留一个 DOM 元素,将其分离/附加到表格以隐藏和显示它。
只需为每个数据项保留一个抽象对象,按需创建一个 DOM 对象来显示它。
哪一个可能会提供最好的用户体验?除了我已经列出的方法之外,还有其他推荐的方法吗?
【问题讨论】:
【参考方案1】:我意识到这并不是你所要求的,但既然你为替补打开了大门......
您是否考虑过在服务器端进行任何过滤?如果用户更改过滤选项,您可以使用 AJAX 加载结果,这样当您可能只显示其中一部分时,您就不会将数千行数据加载到浏览器中。它可能会节省您和访问者的带宽,但这取决于您的网站的实际使用方式。
基本上,如果您提前决定要显示哪些数据,您就不必费力挑选那里的数据。
我知道这可能不符合您的需求,但我将其作为建议,以防您被客户端的想法所困扰。
【讨论】:
我还没有完全关闭做服务器端的事情的大门,我将先评估客户端解决方案,看看它是否有效,感谢您的评论。【参考方案2】:DOM 操作对于“几千个项目”来说太慢了。假设您有一个非常非常好的理由不让服务器进行过滤,那么我发现的最佳解决方案是对保存为 XML 的数据使用客户端 XSL 转换。
即使在相当大的数据集上,转换本身也非常快。然后,您最终会将结果分配给包含 DIV 的您希望表格出现的地方的 innerhtml 属性。使用 innerHTML 对 DOM 进行大的更改比使用 javascript 操作 DOM 快得多。
编辑:对贾斯汀·约翰逊的 cmets 的回答:-
如果数据集那么大,那么 XML 可能会非常大。
请注意,我已经在第一段中就在此处获取服务器帮助做出了免责声明。这里可能有一种情况可以改变设计并合理使用 AJAX,或者干脆不尝试一次显示太多数据。不过我会尽力回答提出的问题。
同样值得考虑的是,“非常大”至少是带宽的函数。在连接良好的 Intranet Web 应用程序中,带宽并不是那么宝贵。此外,我还看到并使用了随着时间的推移构建和重用缓存 XML 的实现。
另外,如果将 XML 转换为 DOM 对象,这会更好吗?
我提出的技术与通过 Javascript 直接操作 DOM 之间存在巨大差异。考虑当 javascript 中的代码修改 DOM 时,底层引擎无法知道其他更改将立即跟随,也不能确定 javascript 不会立即检查 DOM 的其他属性。因此,当 Javascript 对 DOM 进行更改时,浏览器需要确保它更新各种其他属性,以便它们与完成的渲染保持一致。
然而,当 innerHTML 被分配一个大的 HTML 字符串时,浏览器可以很高兴地创建一大堆 DOM 对象而无需进行任何重新计算,它可以推迟对各种属性值的无数次更新,直到整个 DOM 构建完成。因此,对于大规模的更改,innerHTML 将直接对 DOM 进行操作。
【讨论】:
如果数据集那么大,那么 XML 可能会非常大。另外,如果将 XML 转换为 DOM 对象,这会更好吗?【参考方案3】:添加一个类并使用 CSS 显示/隐藏元素可能是最快的(编码和性能方面),尤其是在有这么多项目的情况下。
如果您想走 DOM 操作路线,请考虑离线编辑 DOM。在内存中缓存 DOM 树(一个局部变量),更新所有行并替换原始 DOM 节点。有关此问题的更多信息,请参阅http://www.peachpit.com/articles/article.aspx?p=31567&seqNum=5。
我已经完成了一个项目,该项目需要在 Google 地图“视口”和最小值-最大值滑块中过滤位置上的项目(对于那些好奇的人,它是针对房地产网站的)。
第一个版本使用 AJAX 请求来获取所有(服务器端)过滤项,因此过滤器中的每次更改都请求新数据。然后将 JSON 数据解析为 DOM 节点并添加到文档中。此外,在这种情况下,项目的搜索引擎索引是不可能的。
第二个版本也使用了 AJAX 请求,但这次只请求了过滤后的项目 id。所有项目都存在于具有唯一 ID 的 HTML 中,过滤后的项目有一个额外的类名来最初隐藏它们。每当过滤器更改时,仅请求过滤后的 id 并相应更新项目的类名。这显着提高了速度,尤其是在 Internet Explorer 中(它的 JavaScript 引擎是我们支持的浏览器中最慢的!)...
【讨论】:
我实际上也在做谷歌地图视口过滤,还没有决定是做过滤客户端还是使用 AJAX。听到最后一种技术很有趣,也许可以两全其美。 只有谷歌地图过滤是在客户端完成的,因为我们不想在服务器上进行地理位置过滤(但它当然是可能的)。此外,如果用户没有 JavaScript(打开),谷歌地图和客户端过滤无论如何都不会工作......【参考方案4】:如果显示区域有固定大小(或至少是最大大小),并且您必须在客户端进行过滤,我会不为每个项目创建一个 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?");
* 未测试。不要指望复制/粘贴会起作用,但这会很酷。
【讨论】:
这是个好主意。我最终可能会使用基于客户端页面的导航来缩小(视觉)页面大小,这将为我提供一个可管理的可见项目数量上限。以上是关于使用 JavaScript 在客户端过滤项目、隐藏或从 DOM 中删除的最佳实践?的主要内容,如果未能解决你的问题,请参考以下文章
javascript jQuery搜索过滤,客户端脚本。您需要向包装元素添加一个数据容器,该数据容器将隐藏在不正确的m上