javascript
  • optimization
  • 2013-07-23 7 views 13 likes 
    13

    Używam jQuery to zrobić:pętli wszystkich potomków div - JS tylko

    $element.find("*").each(function() { 
        var $this = $(this); 
    
        $this.removeAttr("style width align"); 
    
        if ($this.is("embed")) { 
         $element.append("<div class='video'></div>"); 
         $this.attr("width", 640).attr("height", 360).parent().appendTo("#" + element + " .video"); 
        }; 
    }); 
    

    Ale czytałem, że .each() metoda jQuery jest dość powolny w porównaniu do zwykłej pętli for (jsPerf). Moje pytanie brzmi: jak mogę to naśladować za pomocą czystego JS? Znajdź wszystkie elementy w obrębie div, a następnie przeprowadź pętlę przez węzły.

    Próbowałem tego szukać, ale wszystko, co mogę znaleźć, to odpowiedzi na jQuery - wszędzie.

    Próbowałem innych rzeczy, ale to było tak blisko, jak mam do wyboru wszystkich potomków:

    var children = document.getElementById('id').getElementsByTagName('*'); 
    
    for(var i = 0; i<children.lengtth; i++){ 
        children[i].removeAttribute("style"); 
        console.log(children[i]); 
    } 
    
    +0

    powodem istnienia jQuery jest dokładnie to ... może być wolniejsze (jak to obchodzi ...), ale to będzie działać na wszystkich przeglądarkach ... czy naprawdę chcesz iteracyjne DOM drzewo i sprawiają, że działa we wszystkich przeglądarkach? – Rufinus

    +0

    [] .slice.call (elm.children) daje tablicę elementów potomnych, podczas gdy [] .slice.call (elm.childNodes) zawiera węzły tekstowe.getElementsByTagName() będzie głębsze niż bezpośrednie dzieci, jeśli tego chcesz. – dandavis

    +1

    Co jest nie tak z rozwiązaniem waniliowym JS? –

    Odpowiedz

    19

    Jesteś już robi to dobrze

    var ancestor = document.getElementById('id'), 
        descendents = ancestor.getElementsByTagName('*'); 
        // gets all descendent of ancestor 
    

    Teraz wystarczy pętli ponad children

    var i, e, d; 
    for (i = 0; i < descendents.length; ++i) { 
        e = descendents[i]; 
        e.removeAttribute('style'); 
        e.removeAttribute('width'); 
        e.removeAttribute('align'); 
        if (e.tagName === 'EMBED') { 
         d = document.createElement('div'); 
         d.setAttribute('class', 'video'); 
         ancestor.appendChild(d); 
        } 
    } 
    

    zależności od tego co robisz, bo używasz getElementsByTagName dostać descendents, descendents jest żywoNodeList, więc jest to długość zmienia się w miarę dodawania kolejnych węzłów do ancestor. Jeśli chcesz tego uniknąć, konwertować je do Array przed pętli

    decendents = Array.prototype.slice.call(decendents); 
    

    Zobacz this gist do wielokrotnego użycia funkcji.

    +0

    LOL moja odpowiedź jest (była: P) pratycznie identyczna z twoją –

    +0

    @LightStyle z wyjątkiem mojej zawiera 'i'mprovised' e'xplosive 'd'evice 8-) –

    +0

    Ponieważ jest to lista live, czy muszę konwertować do tablicy lub czy mogę zapisać długość dokładnie w czasie, kiedy mam zacząć pętlę? –

    3

    czy możesz użyć czegoś tak prostego, jak to?

    // get a handle to the div you want. 
    var div = document.getElementById('someID'), 
        // get an array of child nodes 
        divChildren = div.childNodes; 
    
    for (var i=0; i<divChildren.length; i++) { 
        divChildren[i].style.width = null; 
        divChildren[i].style.textAlign = null; 
    } 
    
    2

    I skomentował w odpowiedzi @Paul S., który mógłby można także klonować węzeł i wykorzystać fragment dokumentu, aby dodać nowe Osadza. Oto przykład:

    HTML:

    <div> 
        <div id="container"> 
         <div align="right">child</div> 
         <div align="center">child</div> 
         <embed src="" width="0" height="0" /> 
         <div align="center">child</div> 
         <div style="width: 40px">child</div> 
         <div style="font-size: 100px">child</div> 
         <div width="60%">child</div> 
         <embed src="" width="0" height="0"/> 
         <div width="60%">child</div> 
        </div> 
    </div> 
    

    JS:

    var elm, 
        clone, 
        doc, 
        next, 
        fragment, 
        live = document.getElementById("container"); 
    
    if (live !== null) { 
        fragment = document.createDocumentFragment(); 
        clone = live.cloneNode(true); 
        next = clone.firstChild; 
        while(next !== null) { 
         if (next.nodeName !== "#text") { 
          next.removeAttribute('style'); 
          next.removeAttribute('width'); 
          next.removeAttribute('align'); 
    
          if (next.tagName === 'EMBED') { 
           doc = document.createElement('div'); 
           doc.setAttribute('class', 'video'); 
           doc.innerHTML = "EMBED detected, adding div..."; 
           fragment.appendChild(doc); 
          } 
         } 
         next = next.nextSibling; 
        } 
        clone.appendChild(fragment); 
        live.parentNode.replaceChild(clone, live); 
    } 
    

    można zobaczyć demo here.

    Klonowanie węzeł zapobiega żywo modyfikację DOM, ponieważ atrybut style może mieć właściwości, które powodują ponowne uruchomienie przeglądarki malować wiele razy.

    1

    Można użyć funkcji querySelectorAll dla forEach.

    document.querySelectorAll('li').forEach(function(element) { 
        console.log(element); 
    }); 
    
    Powiązane problemy