2010-12-28 13 views
2

So habe ich eine Reihe von verschachtelten ul-Elemente als Teil eines Baumes wie unten:Wie kann ich einen DOM-Baum rekrutieren?

<ul> 
<li> 
    <ul> 
     <li>1.1</li> 
     <li>1.2</li> 
    </ul> 
    <ul> 
     <li>2.1</li> 
     <li> 
      <ul> 
       <li>2.2</li> 
      </ul> 
     </li> 
    </ul> 
    <ul> 
     <li>3.1</li> 
     <li>3.2</li> 
    </ul> 
</li> 
</ul> 

sagen wir, wenn 3.1 der ausgewählte Knoten ist und wenn der Benutzer die ausgewählten Knoten vorherigen klickt dann 2,2 sein sollte. Die schlechte Nachricht ist, dass es viele Ebenen geben kann. Wie kann ich den vorherigen Knoten (li) in Bezug auf den aktuell ausgewählten Knoten mit jquery finden?

+0

Wenn 3.2 ausgewählt ist, sollte der vorherige Knoten dann 3.1 sein? – Anurag

+0

@Anurag genau – smartdirt

Antwort

2

Sie können dies in jQuery wie folgt tun:

http://jsfiddle.net/haP5c/

$('li').click(function() { 
    var $this = $(this); 

    if ($this.children().length == 0) { 
     var $lis = $('#myUL').find('li'), 
      indCount = 0, 
      prevLI = null; 

     $lis.each(function(ind, el) { 
      if (el == $this[0]) { 
       indCount = ind; 
       return false; 
      } 
     }); 

     for (indCount=indCount-1; indCount >= 0; indCount--) { 
      if ($($lis[indCount]).children().size() == 0) { 
       prevLI = $lis[indCount]; 
       break; 
      } 
     } 

     if (prevLI) { 
      alert($(prevLI).text()); 
     } 
    } 
}); 

Grundsätzlich, wenn Sie ein Element klicken, wird es für den vorherigen LI Knoten suchen, die keine Kinder haben. Wenn dies der Fall ist, betrachtet es dies als den vorherigen in der Kette. Wie Sie auf der jsfiddle sehen können, funktioniert es perfekt.

+0

Vielen Dank! Es funktioniert super! – smartdirt

1

Ein ziemlich einfacher Ansatz, die ohne JavaScript-Framework funktionieren würde:

var lis = document.getElementsByTagName("li"), prev; 

for (var i = 0; i < lis.length; i++) { 
    if (lis[i] == myCurLI) break; 
    prev = lis[i]; 
} 

Jetzt hält prev den vorherig LI.

EDIT: Bitte beachten Sie meine andere Antwort für eine Lösung mit XPath, die nicht die von treeface genannten Mängel aufweist.

+0

+1, große Antwort! – ifaour

+0

Dies erzeugt nicht das gewünschte Ergebnis [wie Sie hier sehen können] (http://jsfiddle.net/haP5c/1/). – treeface

+0

@treeface: Nun, es funktioniert, aber der Event-Listener wird zu oft aufgerufen. – sjngm

1

Mild „verärgert“ durch die Tatsache, dass mein einfacher Ansatz Mängel hatte, hier eine Lösung mit XPath:

$('li').click(function() { 
    var lis = document.getElementsByTagName("li"), 
     prev = null, 
     myCurLI = this; 

    if ($(this).children().length == 0) { 
     // collect all LI-elements that are leaf nodes 
     var expr = "//li[count(child::*) = 0]", xp, cur; 

     xp = document.evaluate(expr, document, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null); 

     while (cur = xp.iterateNext()) { 
      if (cur == myCurLI) break; 
      prev = cur; 
     } 

     if (prev) alert($(prev).text()); 
     else alert("No previous list element found"); 
    } 
}); 

HINWEIS: kopierte ich den Ereigniscode aus treeface Antwort Handhabung, da ich nicht so vertraut bin mit diesem Rahmen.

+0

Wenn Sie das Bit reparieren, wo Klicken auf 1.1 eine leere Zeichenfolge zurückgibt, haben Sie mein upvote. – treeface

+0

@treeface: Nun, das war eine einfache Lösung. Ich habe das 'if()' am unteren Rand hinzugefügt. – sjngm

+0

Schön gemacht ... habe ein upvote :-) – treeface

5

In DOM wurden Dokumenttraversalklassen definiert, die die sequenzielle Verarbeitung von Bauminhalten ermöglichen. Die TreeWalker- und NodeIterator-Klassen für perfekte Kandidaten dafür.

Zuerst erstellen wir eine TreeWalker-Instanz, die nacheinander durch <li> Knoten iterieren kann.

var walker = document.createTreeWalker(
    document.body, 
    NodeFilter.SHOW_ELEMENT, 
    function(node) { 
      var hasNoElements = node.getElementsByTagName('*').length == 0; 
      return (node.nodeName == "LI" && hasNoElements) ? 
         NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP; 
    }, 
    false 
); 

Als nächstes iterieren wir bis zum aktuellen Knoten in diesem TreeWalker. Nehmen wir an, wir hatten einen Verweis auf unseren aktuellen Knoten in myNode. Wir werden diesen Walker durchlaufen, bis wir myNode oder einen Nullwert erreichen.

while(walker.nextNode() != myNode && walker.currentNode); 

Nachdem wir unseren Knoten in diesem TreeWalker erreicht haben, ist der vorherige Knoten ein Kinderspiel.

var previousNode = walker.previousNode(); 

Sie können versuchen, eine example here.


Hier ist eine generische Version eines rückwärts Baum Walker. Es ist ein kleiner Wrapper um die TreeWalker-Oberfläche.

function backwardsIterator(startingNode, nodeFilter) { 
    var walker = document.createTreeWalker(
     document.body, 
     NodeFilter.SHOW_ELEMENT, 
     function(node) { 
      return nodeFilter(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP 
     }, 
     false 
    ); 

    walker.currentNode = startingNode; 

    return walker; 
} 

Es braucht einen Startknoten und eine benutzerdefinierte Filterfunktion, um unerwünschte Elemente zu entfernen.Hier sehen Sie eine Beispielverwendung, die an einem bestimmten Knoten beginnt und nur Elemente des Typs li enthält.

var startNode = document.getElementById("2.1.1"); 

// creates a backwards iterator with a given start node, and a function to filter out unwanted elements. 
var iterator = backwardsIterator(startNode, function(node) { 
    var hasNoChildElements = node.childElementCount == 0; 
    var isListItemNode = node.nodeName == "LI"; 

    return isListItemNode && hasNoChildElements; 
}); 

// Call previousNode() on the iterator to walk backwards by one node. 
// Can keep calling previousNode() to keep iterating backwards until the beginning. 
iterator.previousNode() 

Aktualisiert mit einem interactive example. Tippen Sie auf ein Listenelement, um das vorherige Listenelement zu markieren.

2

So funktioniert es als jQuery-Plug-In (unter der MIT-Lizenz lizenziert). Laden Sie es gerade nach jQuery geladen:

/* 
* jQuery Previous/Next by Tag Name Plugin. 
* Copyright (c) 2010 idealmachine 
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy 
* of this software and associated documentation files (the "Software"), to deal 
* in the Software without restriction, including without limitation the rights 
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
* copies of the Software, and to permit persons to whom the Software is 
* furnished to do so, subject to the following conditions: 
* 
* The above copyright notice and this permission notice shall be included in 
* all copies or substantial portions of the Software. 
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
* THE SOFTWARE. 
* 
*/ 

(function($) { 
    $.fn.prevByTagName = function(containerSelector) { 
     return this.map(function() { 
      var container = containerSelector ? $(this).parents(containerSelector).last()[0] : document, 
       others = container.getElementsByTagName(this.tagName), 
       result = null; 
      for(var i = 0; i < others.length; ++i) { 
       if(others[i] === this) { 
        break; 
       } 
       result = others[i]; 
      } 
      return result; 
     }); 
    }; 
    $.fn.nextByTagName = function(containerSelector) { 
     return this.map(function() { 
      var container = containerSelector ? $(this).parents(containerSelector).last()[0] : document, 
       others = container.getElementsByTagName(this.tagName), 
       result = null; 
      for(var i = others.length; i--;) { 
       if(others[i] === this) { 
        break; 
       } 
       result = others[i]; 
      } 
      return result; 
     }); 
    }; 
})(jQuery); 

// End of plugin 

Um das letzte vorherige li Element zu finden (die äußersten ul mit der ID myUL), die keine ul Kinder hat, können Sie die Plug-in auf $(this) wie diese verwenden:

var result = $(this); 
while((result = result.prevByTagName('#myUL')).children('ul').length); 

Sie können try it out on jsFiddle.

Verwandte Themen