如果你有一个包含数百个非常简单的子元素的容器div,如下所示:
<div id="stuffContainer" class="item-container">
<div class="single-item"></div>
<div class="single-item"></div>
<div class="single-item"></div>
<div class="single-item"></div>
<div class="single-item"></div>
<div class="single-item"></div>
[...]
</div>
是否会以任何(有意义的)方式包含每个单个元素损害(客户端)性能的唯一ID,无论是渲染,javascript还是内存明智?
为什么我要问:我可能不时需要参考具体的项目,我想弄清楚我是否应该提前预先计算出我需要选择哪些项目,给他们提供ID并离开休息,或者只是为所有人分配id,这会使这个过程更加直接,但我想知道这可能是一种过度杀戮。
奖励积分(如果我能真正给予他们的话),如果有人可以谈论现代浏览器如何处理这个问题,以及为什么它会在浏览器呈现和管理DOM的方式上产生差异。
答案 0 :(得分:3)
最重要的是,我猜测浏览器要做的基本事情是在构建DOM结构时将ID作为属性分配给每个元素,以及将ID存储在哈希表中以方便事物比如#id
选择器,document.getElementById()
和idref查找。我不认为这会导致观察到的性能或内存使用量略有下降,因为散列表和DOM的设计得非常优化。
也就是说,如果您的元素在所有上都不需要ID,那么分配ID就没有意义了;相反,你最终会得到大量的标记膨胀。正如Dan Davies Brackett所提到的, 显然会导致速度放缓,因为它取决于客户端连接。
如果您能够使用CSS选择器引用这些元素,则可以始终使用:nth-child()
来查找特定的子元素。如果您需要支持旧浏览器,那么总会有CSS2解决方案。看到这些问题:
答案 1 :(得分:2)
正如BoltClock所暗示的,大多数性能问题的答案是“衡量它!”。也就是说,您错过了一个潜在的测量轴:下载大小。将ID属性添加到超出必要数量的元素将增加您的字节权重,这不仅仅是因为元素必须是唯一的(这意味着它们不会像非唯一属性一样压缩)。
答案 2 :(得分:2)
原始Q对内容/目的不是很具体,应该有变化,取决于IMO。我当然不同意目前接受的答案。循环并将新ID附加到已经呈现的大量HTML上可能会导致大量的回流计算,这可能会变得很难看,这取决于'stuffContainer'代表什么。
首先从服务器构建ID或在客户端注入单个块(如果必须)
作为一般规则,如果可以避免,请避免重复更改DOM。在浏览器加载页面IMO时,事先在服务器上构建的ID几乎可以忽略不计。当然,它是一个更大的,因此更慢的哈希表,但如果我们谈论数百而不是数万,我真的怀疑你会注意到。
在类似于根据数据构建的选择列表之类的情况下,更高效的客户端方法将首先构建为字符串,使用ID和all,然后分配给容器的innerHTML或者像我的一些js聊天同事,你对每个可能的用例中的innerHTML有一个奇怪的挂断,即使它现在在规范中,至少构建并首先附加到文档片段。然后将其附加到您的容器中。
数据属性或ID上的类
IMO,气味因素并不是关于性能,而是HTML膨胀和创建ID依赖关系,其中不需要任何东西,从而阻止可能在您的一个单项div上找到自定义ID的其他东西。 ID肯定是缩小JavaScript中元素查找范围的理想方式,但是对于包含内容的容器,您可以从ID'd容器中获得比ID每个子项更多的灵活性。单步执行与双步执行的性能提升不值得将通用ID应用于元素的灵活性成本。
作为替代方案,您可以使用具有唯一值或数据属性的类,例如'数据的itemId = “0”'。对于较小的HTML集合,例如自定义选择列表,其中ID连接到某些服务器端索引系统以便于更新数据,我倾向于支持这种高度可见的方法,因为它使得更容易理解架构,但它增加了很多在可能涉及数百到数千个项目的情况下跟踪不必要的属性。
或理想情况下(在大多数情况下),事件委派
最理想的情况是,IMO,如果你只关心你点击的儿童单项元素,而不是'ID'是或这些单一的顺序,你会完全避免使用其他属性-item容器将保持静态,您可以安全地假设这些位置是有效ID。或者这可能与非静态单项集合一起使用的另一种情况是,如果您在对象数组中获得了单项数据,这些数据会被洗牌,然后用于在用户启动的排序上构建和替换HTML将HTML的顺序与其他数据跟踪依赖关系联系起来。
非Jquery方法(未经测试):
var myContainer = document.getElementById('stuffContainer');
//ignore following indent goof
myContainer.addEventListener('click', function(e){
var
singleItem,
elementOriginallyClicked = singleItem = e.target,
stuffContainer = this;
//anything clicked inside myContainer will trigger a click event on myContainer
//the original element clicked is e.target
//google 'event bubbling javascript' or 'event delegation javascript' for more info
//climb parentNodes until we get to a single-item node
//unless it's already single-item that was originally clicked
while( !singleItem.className.match(/[=\s'"]single-item[\s'"]/g) ){
singleItem = singleItem.parentNode;
}
//You now have a reference to the element you care about
//If you want the index:
//Get the singleItem's parent's childNodes collection and convert to array
//then use indexOf (MDN has normalizer for IE<=8) to get the index of the single-item
var childArray = Array.prototype.slice.apply(stuffContainer.childNodes,[0]),
thisIndex = childArray.indexOf(singleItem);
doSomethingWithIndex(thisIndex);
//or
//doSomethingWithDOMObject(singleItem);
} );
或简单的JQuery委托样式(也是未经测试的):
$('#someContainer').on('click','.single-item', function(){
var $_singleItem = $(this), //jq handles the bubble to the interesting node for you
thisIndex = $_singleItem.index(); //also getting index relative to parent
doSomethingWithIndex(thisIndex);
//or
//doSomethingWithJQObject($_thisItem);
} );
答案 3 :(得分:1)
即使使用了数百次,使用id
属性也没有明显的性能下降。虽然手动挑选您需要唯一识别的元素会稍微快一点,但在我看来,性能提升并不能证明这样做所需的额外时间。
话虽如此,我不确定在这种情况下甚至需要id
属性。如果您要使用jQuery,则可以选择第四个元素,例如,使用以下代码:
$('.single-item').eq(3);
答案 4 :(得分:0)
在这种情况下,在所有内容上使用id会有点矫枉过正。我知道你来自哪里,但如果你使用像jQuery这样的语言,那么选择孩子会很容易考虑结构。下面是一个例子,说明如何知道哪个div被点击了:
$('.single-item').click(function()
{
var yourClickedDiv = $(this);
// execute the rest of your code here
});
这只是一个小例子,但正如您所看到的,您可以访问每个div,无论您需要做什么。这样可以避免html文件与过多的id标签混在一起,同时保持文件大小更小一点(更不用说为您节省生成每个唯一ID的麻烦)。