簡體   English   中英

如何對DOM元素進行排序,從而觸發最少量的回流?

[英]How can I sort DOM elements triggering the least amount of reflow?

我有以下例子。

<div class="parent">
  <div data-id="5"></div>
  <div data-id="2"></div>
  <div data-id="3"></div>
  <div data-id="1"></div>
  <div data-id="4"></div>
</div>

如果我想按升序(1,2,3,4,5)訂購這些div。 我通常會做一個循環並將div添加到parent div。 然而,這意味着我總是對dom進行5次更改(無論div的順序如何),每個div一次。

但是,你可以使用.insertBefore()方法只需2次更改即可正確排序div!

5,2,3,1,4
Insert 1 before 2
5,1,2,3,4
Insert 5 behind 4 (using .insertBefore() and .nextSibling)
1,2,3,4,5 

問題1通過僅對DOM進行2次更改,我假設回流次數較少,使“2次更改”排序操作比“5次更改”操作更快。 這個對嗎?

問題2什么樣的方法/算法能夠確定只5 behind 45 behind 4插入1 before 2

問題3(獎金)隨着物品數量的增加,這種“優化”算法會更快嗎? 范圍10 - 100 - 1.000 - 10.000 - 100.000

也許澄清一下:不是在尋找一種以最佳方式找出順序(1,2,3,4,5)的方法。 在某一點我知道訂單,但我想再次比較div的順序,然后THEN計算出最少的操作量

對瀏覽器的功能更有信心。

  1. 當瀏覽器在一個單一的同步執行JavaScript序列中執行時,瀏覽器將DOM操作批處理在一起。 當您通過訪問需要DOM為最新的DOM屬性/方法(例如innerWidthoffsetTopgetBoundingClientRect )來明確地(有時是在不知不覺中)請求重排時,會發生異常。 有關詳細信息請參見渲染:重繪重排,重新設計。
    刪除DOM節點不是必需的。 將它們添加到新創建的DocumentFragment ,它們將自動從DOM中的當前位置移除。

  2. 瀏覽器,更具體地說是JS引擎,已經知道並使用最智能的排序算法。 除特定情況外,您無需了解排序操作的內部機制。 只需使用Array.prototype.sort ,必要時提供自定義功能,並觀察魔法發生。

從DOM中刪除所有節點,並在代碼中對它們進行排序后按正確的順序替換它們。

HTML:

<div id="wrapper">
  <div id="par" class="parent">
    <div id="5">5</div>
    <div id="2">2</div>
    <div id="3">3</div>
    <div id="1">1</div>
    <div id="4">4</div>
  </div>
</div>

使用Javascript:

var clone = document.getElementById("par")
  .cloneNode(true)
var childs = [].slice.call(clone.children);
var sorted = childs.sort(function(a, b) {
  return parseInt(a.id) - parseInt(b.id)
})
var frag = document.createDocumentFragment();
sorted.forEach(function(el) {
  frag.appendChild(el)
})

var wrapper = document.getElementById("wrapper");
wrapper.removeChild(document.getElementById("par"));
wrapper.appendChild(frag);

說明:單個DOM操作比排序算法中的算法步驟重。

如果數字變大,最智能的排序算法需要O(n log n)倍的節點數。 這意味着n * log(n)DOM操作。 在人類語言中,這只是節點數量的幾倍。

但是如果你只是刪除所有節點,然后以正確的順序再次添加它們,那么最壞的情況下會得到n + 1個DOM操作。 可能你可以將所有節點添加到一起,你最終會得到一個更接近2 / O(1)的數字 ,但我並不專注於現代瀏覽器實際完成的速度,所以讓我們繼續使用n + 1 ,保守地說。

現在到了數字:

假設你有5個節點。 在這種情況下,一切都很好,數字很小,但為了你自己的平安,以及你和你的同事的未來和平,你想寫一個清晰的算法。 因此,刪除所有節點並按正確的順序替換它們。

現在說你有1000個節點。 在這種情況下,排序將需要大約10,000次操作(n * log n = 1000 * 10)**。 如果將每個節點分別放在那里,則將有10,000個DOM操作。

相反,如果您只是從DOM中刪除節點,在javascript代碼中對它們進行排序,然后將它們重新放入,那么您將只有1000個DOM操作。 這是相當保守的,因為我覺得它實際上只需要2個DOM操作:一次刪除所有節點,一次以正確的順序添加所有節點***

**我寧願給出難以理解的數字,只是為了弄清楚這一切。 基於1024的基數2,即10 ***這可能是真正的差異所在。 如果有人知道,請評論/編輯!

請看一下這段代碼。

基本上它從dom中移除容器,應用排序,將其重新插入dom。

通常這一切都可以在一幀重繪中發生,因此不會影響頁面/滾動問題的長度

 +function() { /** * Finding thing wrapping class */ var $con = $('#container'); /** * getting the parent of the wrapping class so we can reinsert when we're done. */ var $parent = $con.parent(); /** * Removing container from dom so we can sort in speed */ $con.remove(); /** * Getting the things we need from container that we need to sort */ var $tosort = $con.find('.thing'); /** * Apply sorting algorything, get a newly sorted list */ var $neworder = $tosort.sort(function(a,b){ return parseInt(a.innerText) > parseInt(b.innerText); }); /** * Simply append the newly ordered list. They are the same objects, not clones so they'll fit into the right order. */ $con.append($neworder); /** * Reinsert container into the dom. */ $parent.append($con); }() 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="wrap"> <div id="container"> <div class="thing"> 4 </div> <div class="thing"> 3 </div> <div class="thing"> 1 </div> <div class="thing"> 5 </div> <div class="thing"> 2 </div> </div> </div> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM