2016-07-29 17 views
2

Ich erstelle dynamisch eine SEHR große HTML-Datei mit so vielen Elementen, wie der Browser auf einem bestimmten Computer erzeugen kann.Schnellste Möglichkeit, Elemente im Ansichtsfenster zu erhalten

Ich muss dann, wenn der Benutzer scrollt, auf die Elemente eines bestimmten Typs (sagen wir div) zugreifen, die sich tatsächlich im Ansichtsfenster befinden.

Die einzige Möglichkeit, wie ich eine Liste der im Ansichtsfenster sichtbaren Elemente erhalten kann, besteht darin, alle Elemente zu durchlaufen und dann zu sehen, ob ihre Grenzen sich mit dem aktuellen Ansichtsfenster überschneiden. Das Problem dabei ist, dass es im Dokument so viele Elemente gibt, dass dieser Prozess nicht schnell genug abgeschlossen werden kann, um den Browser scrollen zu lassen.

Gibt es eine schnellere Möglichkeit, alle Elemente im Ansichtsfenster zu erhalten?

+0

sind all diese Elemente in einer Listenansicht? – Wolfgang

+0

haben diese Antwort gefunden - http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport – marmeladze

+0

Wenn Sie generieren Eltern-Knoten für große Gruppen von Knoten können Sie einen Listener verfolgen, welcher Elternteil sich im Darstellungsbereich befindet (wie http://imakewebthings.com/waypoints/) und dann eine Sichtbarkeitsprüfung (wie die mit @marmeladze verknüpfte) durchführen lassen für Kinder dieses Elternteils –

Antwort

0

Teile und herrsche

Sie können den Bereich des Fensters in kleinere Bereiche unterteilen (FNO Blöcke). Wenn die Website hauptsächlich vertikal ausgerichtet ist, benötigen Sie nicht mehr als eine Spalte (die Blockbreite entspricht der Dokumentbreite). Nachdem Sie die Seite aufgefüllt haben, fügen Sie jeden Knoten und seine Nachkommen den Blöcken hinzu, in denen sie sich befinden (sie können in mehreren Blöcken sein). Im Scroll-Event-Handler müssen Sie nur die Knoten in den sichtbaren Blöcken prüfen. Wenn die Höhe jedes Blocks der Höhe des Ansichtsfensters entspricht, müssen Sie nur bis zu zwei Blöcke prüfen. Und egal, wie groß die Seite ist, finden Sie immer die Blöcke wie folgt:

var from = Math.trunc(viewport.y/blockHeight) ; 
var to = Math.trunc(viewport.y2/blockHeight) ; 

Im folgenden Beispiel habe ich dinamically 10.500 Knoten erstellen, danach können Sie die Seite und die sichtbaren divs scrollt aufgeführt sein. Sie können die Funktion Matchs anpassen, wenn Sie die Knoten anders filtern möchten. Ich testete dies in meinem Tablet mit Chrome und 200.000 Knoten, nachdem die Seite geladen wurde, war die Schriftrolle glatt. Die Leistung kann fallen, wenn Sie mehr Knoten hinzufügen, als der Computer/Browser verarbeiten kann. Der Algorithmus funktioniert einwandfrei. Mit der gleichen Testmaschine und 1.000.000 Knoten fand das Scrollen nicht in Echtzeit statt, aber es war nicht so langsam.

Das Laden der Seite dauert einige Zeit, bitte haben Sie etwas Geduld.

var blocks = [] ; 
 
var blockHeight ; 
 
var blocksNumber ; 
 
function isVisible(element, vp) 
 
{ 
 
    /* This checks if the element is in the viewport area, you could also 
 
    * check the display and visibility of its style. 
 
    */ 
 
    var rect = element.getBoundingClientRect() ; 
 
    var x = rect.left ; 
 
    var x2 = x + element.offsetWidth ; 
 
    var y = rect.top ; 
 
    var y2 = y + element.offsetHeight ; 
 
    return !(x >= vp.w || y >= vp.h || x2 < 0 || y2 < 0) ; 
 
} 
 
function matches(element, vp) 
 
{ 
 
    /* You can filter the elements even further */ 
 
    return element && element.id && element.tagName === "DIV" && isVisible(element, vp) ; 
 
} 
 
function viewport() 
 
{ 
 
    this.x = window.pageXOffset ; 
 
    this.w = window.innerWidth ; 
 
    this.x2 = this.x + this.w - 1 ; 
 
    this.y = window.pageYOffset ; 
 
    this.h = window.innerHeight ; 
 
    this.y2 = this.y + this.h - 1 ; 
 
    return this ; 
 
} 
 
function addMatch(element, array) 
 
{ 
 
    /* An element may be in more than one block, so you need 
 
    * to check if it wasn't already added. 
 
    */ 
 
    for(var i = 0 ; i < array.length ; ++i) 
 
    { 
 
     if(array[i] === element) return ; 
 
    } 
 
    array.push(element) ; 
 
} 
 
function onWindowScroll() 
 
{ 
 
    var msg = document.getElementById("msg") ; 
 
    var str = "" ; 
 

 
    var vp = new viewport() ; 
 
    var from = Math.trunc(vp.y/blockHeight) ; 
 
    var to = Math.trunc(vp.y2/blockHeight) ; 
 
    str += "Nodes: " + document.body.childNodes.length 
 
     + ", blocks: " + blocks.length 
 
     + ", searching blocks " + from + "-" + to + "<br>" 
 
     + "Founded: " ; 
 
    var array = [] ; 
 
    for(var b = from ; b <= to ; ++b) 
 
    { 
 
     var block = blocks[b] ; 
 
     for(var i = 0 ; i < block.length ; ++i) 
 
     { 
 
      if(matches(block[i], vp)) 
 
      { 
 
       addMatch(block[i], array) ; 
 
      } 
 
     } 
 
    } 
 
    if(array.length) 
 
    { 
 
     for(var i = 0 ; i < array.length-1 ; ++i) 
 
     { 
 
      str += array[i].id + " " ; 
 
     } 
 
     str += array[array.length-1].id ; 
 
    } 
 
    else 
 
    { 
 
     str += "none" ; 
 
    } 
 
    msg.innerHTML = str ; 
 
} 
 
function onWindowLoad() 
 
{ 
 
    setTimeout(function() 
 
    { 
 
     var i = 0 ; 
 
     /* Lets populate the page */ 
 
     while(i < 10000) 
 
     { 
 
      var element = document.createElement("DIV") ; 
 
      element.className = "first" ; 
 
      element.innerHTML = i ; 
 
      element.id = i++ ; 
 
      document.body.appendChild(element) ; 
 
      element = document.createElement("SECOND") ; 
 
      element.className = "second" ; 
 
      element.innerHTML = i ; 
 
      element.id = i++ ; 
 
      document.body.appendChild(element) ; 
 
     } 
 
     /* Lets add random positioned elements */ 
 
     var i = 0 ; 
 
     while(i < 500) 
 
     { 
 
      var x = Math.floor(Math.random() * document.body.offsetWidth) ; 
 
      var y = Math.floor(Math.random() * document.body.offsetHeight) ; 
 
      if(Math.random() < 0.5) 
 
      { 
 
       var element = document.createElement("DIV") ; 
 
       element.className = "absolute-first" ; 
 
      } 
 
      else 
 
      { 
 
       var element = document.createElement("SECOND") ; 
 
       element.className = "absolute-second" ; 
 
      } 
 
      element.style.left = x + "px" ; 
 
      element.style.top = y + "px" ; 
 
      element.id = "r" + i++ ; 
 
      element.innerHTML = element.id ; 
 
      document.body.appendChild(element) ; 
 
     } 
 
     /* Now we create the blocks */ 
 
     var nodes = document.body.childNodes ; 
 
     blockHeight = window.innerHeight ; 
 
     blocksNumber = Math.ceil(document.body.offsetHeight/blockHeight) ; 
 
     for(var b = 0 ; b < blocksNumber ; ++b) 
 
     { 
 
      blocks[b] = new Array() ; 
 
     } 
 
     /* And we add all the nodes into they corresponding blocks */ 
 
     for(var i = 0 ; i < nodes.length ; ++i) 
 
     { 
 
      addElement(nodes[i]) ; 
 
     } 
 
     addEventListener("scroll", onWindowScroll, false) ; 
 
     onWindowScroll() ; // Initialize msg 
 
    }, 20) ; 
 
} 
 
function addElement(element) 
 
{ 
 
    /* This works fine if the rest of the nodes stayed in the 
 
    * same position with the same size when element was added. 
 
    */ 
 
    if(!element.getBoundingClientRect) return ; 
 
    var rect = element.getBoundingClientRect() ; 
 
    var y = rect.top + window.pageYOffset ; 
 
    var y2 = y + element.offsetHeight ; 
 
    var from = Math.trunc(y/blockHeight) ; 
 
    var to = Math.trunc(y2/blockHeight) ; 
 
    for(var b = from ; b <= to ; ++b) 
 
    { 
 
     blocks[b].push(element) ; 
 
    } 
 
    var nodes = element.childNodes ; 
 
    if(nodes) 
 
    { 
 
     for(var i = 0 ; i < nodes.length ; ++i) 
 
     { 
 
      addElement(nodes[i]) ; 
 
     } 
 
    } 
 
} 
 
function removeElement(element) 
 
{ 
 
    /* This works fine if the rest of the nodes stayed in the 
 
    * same position with the same size when element was added. 
 
    */ 
 
    if(!element.getBoundingClientRect) return ; 
 
    var rect = element.getBoundingClientRect() ; 
 
    var y = rect.top + window.pageYOffset ; 
 
    var y2 = y + element.offsetHeight ; 
 
    var from = Math.trunc(y/blockHeight) ; 
 
    var to = Math.trunc(y2/blockHeight) ; 
 
    for(var b = from ; b <= to ; ++b) 
 
    { 
 
     var i = blocks[b].indexOf(element) ; 
 
     if(i > -1) 
 
     { 
 
      blocks[b].splice(i, 1) ; 
 
     } 
 
    } 
 
} 
 
addEventListener("load", onWindowLoad, false) ;
body 
 
{ 
 
    margin: 0 auto ; 
 
    text-align: center ; 
 
    font-family: sans-serif ; 
 
} 
 
/* Filtered in elements are light green */ 
 
.first 
 
{ 
 
    height: 50px ; 
 
    line-height: 50px ; 
 
    background-color: #cfc ; 
 
} 
 
/* Filtered out elements are light red */ 
 
.second 
 
{ 
 
    display: block ; 
 
    height: 30px ; 
 
    line-height: 30px ; 
 
    background-color: #fcc ; 
 
    box-sizing: border-box ; 
 
} 
 
/* Filtered in elements are light green */ 
 
.absolute-first 
 
{ 
 
    background-color: #cfc ; 
 
} 
 
/* Filtered out elements are light red */ 
 
.absolute-second 
 
{ 
 
    background-color: #fcc ; 
 
} 
 
.absolute-first, .absolute-second 
 
{ 
 
    position: absolute ; 
 
    padding: 1pt 5pt 1pt 5pt ; 
 
} 
 
.first, .second, .absolute-first, .absolute-second 
 
{ 
 
    border: 1px solid #444 ; 
 
} 
 
#msg 
 
{ 
 
    position: fixed ; 
 
    z-index: 1 ; 
 
    top: 0 ; 
 
    left: 0 ; 
 
    width: 100% ; 
 
    min-height: 24pt ; 
 
    line-height: 24pt ; 
 
    border: 1px solid #000 ; 
 
    background-color: #ffd ; 
 
    box-sizing: border-box ; 
 
    font-size: 14pt ; 
 
    vertical-align: middle ; 
 
    text-align: left ; 
 
    padding-left: 3pt ; 
 
    opacity: 0.7 ; 
 
}
<div id="a"> 
 
    <div id="a1"> 
 
     <div id="a11" class="first">a11</div> 
 
     <div id="a12" class="first">a12</div> 
 
    </div> 
 
    <div id="a2" class="first">a2</div> 
 
</div> 
 
<msg id="msg">Loading page, please wait...</msg>

Der einzige Nachteil ist, dass Sie die Knoten in den entsprechenden Blöcken zu halten haben. Die Blöcke sollten aktualisiert werden, wenn Sie einen neuen Knoten hinzufügen, wenn Sie einen vorhandenen Knoten entfernen oder wenn ein Knoten verschoben oder in der Größe geändert wird. Dies sollte kein Problem sein, da Sie gesagt haben, dass Sie zuerst die Seite füllen.

Die fest positionierten Knoten werden nicht berücksichtigt. Es ist einfach, Unterstützung für sie hinzuzufügen, aber es würde dem Beispiel nichts Wertvolles hinzufügen.