来自https://developers.google.com/speed/articles/javascript-dom
根据我的理解,追加/删除元素会导致重排。和改变班级一样。但是在解决方案中,您将附加和删除,从而导致两次次重排作为问题代码。当然,并非所有的回流都是相同的,所以类名改变回流比追加/去除回流更昂贵吗?我错过了什么使得解决方案代码比问题代码更有效?
这种模式让我们可以创建多个元素并将它们插入到 DOM触发单个回流。它使用一种叫做a的东西 DocumentFragment的。我们在DOM之外创建一个DocumentFragment(所以 它是不合时宜的。然后我们创建并添加多个元素 这个。最后,我们将DocumentFragment中的所有元素移动到DOM 但会触发一次回流。
问题
让我们创建一个更改所有className属性的函数 元素内的锚点。我们可以通过简单迭代来做到这一点 通过每个锚点并更新其href属性。问题 是的,这可能导致每个锚点的重绕。
function updateAllAnchors(element, anchorClass) { var anchors = element.getElementsByTagName('a'); for (var i = 0, length = anchors.length; i < length; i ++) { anchors[i].className = anchorClass; } }
解决方案
要解决这个问题,我们可以从DOM中删除元素,进行更新 所有锚点,然后将元素插回原处。帮助 实现这一点,我们可以编写一个不仅可以删除的可重用函数 来自DOM的元素,但也返回将插入的函数 元素回到原来的位置。
/** * Remove an element and provide a function that inserts it into its original position * @param element {Element} The element to be temporarily removed * @return {Function} A function that inserts the element into its original position **/ function removeToInsertLater(element) { var parentNode = element.parentNode; var nextSibling = element.nextSibling; parentNode.removeChild(element); return function() { if (nextSibling) { parentNode.insertBefore(element, nextSibling); } else { parentNode.appendChild(element); } }; }
现在我们可以使用此函数来更新元素中的锚点 这是流动的,只有当我们删除时才触发重排 元素和插入元素时。
function updateAllAnchors(element, anchorClass) { var insertFunction = removeToInsertLater(element); var anchors = element.getElementsByTagName('a'); for (var i = 0, length = anchors.length; i < length; i ++) { anchors[i].className = anchorClass; } insertFunction(); }
答案 0 :(得分:2)
假设您要更改100万个元素的类。
直接这样做会导致100万次回流 - 每个班级 - 。
但是如果从DOM中删除它的父项,更改所有类,并将其重新插入,那只有2次重排 - 因为文档外部的更改元素不会导致重排 - 。
所以基本上,如果你有很多元素,删除和重新插入会更有效。如果你只有几个,就不需要这样做。
答案 1 :(得分:1)
因此,文档片段存在于内存中,而不是在页面上。操作不会触发任何重新绘制/流动,因为片段在任何地方都无法直观显示。当你把它放在页面上时,一旦你完成操作它,浏览器就会知道它的结构,类,内容等,所以只需要重排/绘制一次。
在第一个示例中,当您遍历锚点并更改类名称(可能也改变其样式)时,它将立即应用该类,找到新样式并重新绘制该链接。然后为下一个做同样的事情。这很慢。
通过将其全部放入内存并在那里操作DOM,当您将父包装元素重新插入页面时,只有一个重绘/流。
答案 2 :(得分:1)
根据解决方案:
要解决这个问题,我们可以从DOM中删除元素,进行更新 所有锚点,然后将元素插回到原来的位置。
因此,在这种情况下,它将触发2次回流(一次用于移除,一次用于插入)。因此,当您想要一次修改2个以上的元素时,此解决方案适用。