12. januar 2010 - 18:12Der er
18 kommentarer og 1 løsning
Hvordan vælges alle elementer af typen <li> pånær ét
Hej.
Jeg er ved at lave et lille script, som ændrer ændrer baggrundsfarven på noge <li> elementer. Baggrundsfarven skal f.eks. være rød, men på det <li> element som man trykker på skal være grøn.
Mit eks. er gjort en s mule mere simpelt. Dir svar virker perfekt i eks. men desværre ikke i den lidt mere komplecerede struktur.
<div id="myTest"> <ul> <li onclick="changeColor(this);"> Test a <ul> <li> Test a.1 </li> <li> Test a.2 <ul> <li> Test a.2.1 </li> </ul> </li> <li> Test a.3 </li> </ul> </li> <li> Test b </li> <li> Test c <ul> <li> Test c.1 </li> </ul> </li> <li> Tect d </li> </ul> </div>
Først led af <ul> skal altid være grøn, men <li> med tilhørende <ul> skal den tilhørende <ul> blive grøn. De resterende <ul> i diven skal skifte til rød.
Så har jeg tænkt at jeg ville lave en if sætning der sammenlignede de fundende <ul>'er med mit elm. Hvis de er lig hinanden sættes farven til grøn ellers sættes den til rød. Dette gør blot aller <ul>'erne grønne. :(
Jeg forstår ikke hvad der skal være grøn og rød... Det her giver ingen mening for mig: "Først led af <ul> skal altid være grøn, men <li> med tilhørende <ul> skal den tilhørende <ul> blive grøn. De resterende <ul> i diven skal skifte til rød."
<script type="text/javascript">8 function changeColor(elm) { elm.getElementsByTagName('ul')[0].style.background = 'green'; } </script>
<div id="myTest"> <ul> <!-- Denne <ul> og de tilhørende <li> skal altid være grønne --> <li onclick="changeColor(this);"> Test a <ul> <li> Test a.1 </li> <li onclick="changeColor(this);"> Test a.2 <ul> <!-- Denne <ul> og de tilhørende <li> skal skifte grøn når der klikkes på ovenstående <li> --> <li> Test a.2.1 </li> </ul> </li> <li> Test a.3 </li> </ul> </li> <li> Test b </li> <li onclick="changeColor(this);"> Test c <ul> <!-- Denne <ul> og de tilhørende <li> skal skifte grøn når der klikkes på ovenstående <li> --> <li> Test c.1 </li> </ul> </li> <li> Test d </li> </ul> </div>
Hvis jeg f.eks. klikker på [Test a], skal [Test a.1], [Test a.2] og [Test a.3] skifte til grønne. Hvis jeg efterfølgende klikker på [Test c] skal [Test c.1] skifte til grøn og [Test a.1], [Test a.2] og [Test a.3] skal så skifte tilbage til rød.
Ja, det giver mere mening. Jeg har ændret lidt i den ul struktur, så under punkterne først startes efter <li> er afsluttet og ikke indeni. Det gør det nemmere at arbejde med.
Eksempel: <script> function changeColor(e) { div = document.getElementById('myTest'); ul_elements = div.getElementsByTagName('ul');
for (var i=0; i<ul_elements.length; i++) { li_elements = ul_elements[i].getElementsByTagName('li'); for (var j=0; j<li_elements.length; j++) { // gør altid li fra første ul element grøn og alle andre røde if (i == 0) { li_elements[j].className = 'green'; } else { li_elements[j].className = 'red'; }
// gør det element vi klikkede på grønt if (li_elements[j] == e) { li_elements[j].className = 'green'; } } }
var nextElement = e.nextSibling; // hent næste element if (nextElement != null) { // vi skal være sikker på det er et element og ikke en blank while (nextElement != null && nextElement.nodeType !=1) { nextElement = nextElement.nextSibling; }
if (nextElement != null) { next_li_elements = nextElement.getElementsByTagName('li'); // hent eventuelle li elementer if (next_li_elements.length > 0) { // er der nogen li elementer for (var i=0; i<next_li_elements.length; i++) { // lav dem grønne next_li_elements[i].className = 'green'; } } } } }
<div id="myTest"> <ul> <!-- Denne <ul> og de tilhørende <li> skal altid være grønne --> <li onclick="changeColor(this);"> Test a </li> <ul> <li> Test a.1 </li> <li onclick="changeColor(this);"> Test a.2 </li> <ul> <!-- Denne <ul> og de tilhørende <li> skal skifte grøn når der klikkes på ovenstående <li> --> <li> Test a.2.1 </li> </ul> <li> Test a.3 </li> </ul> <li> Test b </li> <li onclick="changeColor(this);"> Test c </li> <ul> <!-- Denne <ul> og de tilhørende <li> skal skifte grøn når der klikkes på ovenstående <li> --> <li> Test c.1 </li> </ul> <li onclick="changeColor(this);"> Test d </li> </ul> </div>
Min kode ser pt. sådan ud: <html> <head> <script> function changeColor(e) { div = document.getElementById('myTest'); ul_elements = div.getElementsByTagName('ul');
for (var i=0; i<ul_elements.length; i++) { li_elements = ul_elements[i].getElementsByTagName('li'); for (var j=0; j<li_elements.length; j++) { // gør altid li fra første ul element grøn og alle andre røde if (i == 0) { li_elements[j].className = 'green'; } else { li_elements[j].className = 'red'; }
// gør det element vi klikkede på grønt if (li_elements[j] == e) { li_elements[j].className = 'green'; } } }
var nextElement = e.nextSibling; // hent næste element if (nextElement != null) { // vi skal være sikker på det er et element og ikke en blank while (nextElement != null && nextElement.nodeType !=1) { nextElement = nextElement.nextSibling; }
if (nextElement != null) { next_li_elements = nextElement.getElementsByTagName('li'); // hent eventuelle li elementer if (next_li_elements.length > 0) { // er der nogen li elementer for (var i=0; i<next_li_elements.length; i++) { // lav dem grønne next_li_elements[i].className = 'green'; } } } } } </script> <style> #myTest { width: 150px; } ul { list-style-type: none; padding-left: 15px; background: green; } li:hover, li.red:hover, li.green:hover { cursor: pointer; background: yellow; } li.red { background: red; } li.green { background: green; } </style> </head>
Jeg har lavet den færdig for dig, der er et par krumspring i koden, da internet explorer (som sædvanligt) ikke mener de skal overholde standarderne. Udover det har jeg kommenteret hvad jeg mente var nødvendigt, du kan bare spørge hvis der er noget.
<html> <head> <script> var t = null; function changeColor(e) { t = null; div = document.getElementById('myTest'); ul_elements = div.getElementsByTagName('ul');
// sæt indledende farver på LI for (var i=0; i<ul_elements.length; i++) { li_elements = ul_elements[i].getElementsByTagName('li'); for (var j=0; j<li_elements.length; j++) { // gør altid li fra første ul element grøn og alle andre røde if (i == 0) { li_elements[j].className = 'green'; } else { li_elements[j].className = 'red'; }
} }
// Gør valgt element + siblings/parents af klikkede element grønne e_parent = e.parentNode; while(e_parent.nodeName == 'UL') { li_elements = e_parent.getElementsByTagName('li'); for (var j=0; j<li_elements.length; j++) { // kun første niveau af UL skal være grønt, ikke underliggende niveauer if (li_elements[j].parentNode == e_parent) { li_elements[j].className = 'green'; } } e_parent = e_parent.parentNode; }
// gør næste UL element grønt, hvis der er et var nextElement = e.nextSibling; // hent næste element if (nextElement != null) { // vi skal være sikker på det er et element og ikke et linjeskift eller lign. while (nextElement != null && nextElement.nodeType !=1) { nextElement = nextElement.nextSibling; }
// hack så internet explorer fatter det if (e.sourceIndex != undefined) { ie_element = document.all[e.sourceIndex+1]; if (ie_element.nodeName == 'UL') { nextElement = ie_element; } } if (nextElement != null) { if (nextElement.nodeName == 'UL') { // er næste element en UL? next_li_elements = nextElement.getElementsByTagName('li'); // hent eventuelle li elementer
if (next_li_elements.length > 0) { // er der nogen li elementer for (var i=0; i<next_li_elements.length; i++) { // lav dem grønne if (next_li_elements[i].parentNode == nextElement) { next_li_elements[i].className = 'green'; } } } } } } }
// Internet explorer hack, så den ikke kører eventet for alle niveauer samtidigt når man klikker function loadChange(e) { if (t == null) { t = setTimeout(function() {changeColor(e)}, 10); } }
Har forsøgt at rette koden lidt til. Den tilrettet kode virker perfekt i IE8, FF, Safari og Chrome, men desværre ikke i IE7 :(
Kan du lede mig på rette spor i forhold til hvad jeg gør forkert?
function changeColor(e) { var myUls = document.getElementById('myMenu').getElementsByTagName('ul'); var parentUl = e.parentNode; var nextUl = e.nextSibling;
// skjul alle ul-elementer i myMenu div-elementet for(var i = 0; i < myUls.length; i++) { myUls[i].className = 'red'; }
// viser alle de ul-elementer der omkredser li-elementet, der blev trykket på while(parentUl.nodeName == 'UL') { parentUl.className = 'green'; parentUl = parentUl.parentNode; }
// sikrer at det næste element er et element og ikke en blank if (nextUl != null) { while (nextUl != null && nextUl.nodeType !=1) { nextUl = nextUl.nextSibling; } }
// hvis næste element er af typen UL vises dette if (nextUl.nodeName == "UL") { nextUl.className = "green"; } }
Ahh kan nu se, at du har smidt en løsning. :) Men for min egen tilfredsheds skyld, kan du så hjælpe med ovenstående, så skal du få dine velfortjente 200 points.
Jeg har tilrettet koden for at lærer mest muligt selv, så nej jeg ønsker ikke, at du skal ændre det jeg har lavet så det virker, men håbede, at du ville lede mig på rette spor, så jeg selv kunne få det til at virke.
Fair nok :) Jeg kan godt lige skrive de par ting jeg rendte ind i med internet explorer (koden fremgår af kommentarene i koden).
Når jeg klikkede på et nested element i UL listen, aktiverede IE først det 'rigtige' onclick. Derefter onclick for den parent, og herefter igen for den parent osv.
Det omgik jeg ved at lave en setTimeout på onclick i stedet. Så den kun kører det første onclick (derfor jeg sætter t=null i selve funktionen. setTimeout gør, at den når at registrere alle onclick events (både det rigtige og alle de forkerte) inden funktionen køres. Når funktionen kører sætter jeg t=null, og der kan derved laves en ny onclick næste gang man klikker. Så kort sagt, slår den fra efter først event er registreret, og slår til igen 10 millisekunder senere.
Den anden fejl var nextUl.nextSibling. IE mente, at nextSibling var et LI element, på trods af, at det i virkeligheden var et UL element (prøv at lav en alert(e.parentNode.nodeName) og se hvad den siger. IE har tilgengæld en metode der kunne hente sourceIndex. sourceIndex er det index nummer elementerne har (fra 0-xxx). Firefox f.eks. siger at sourceIndex er undefined. Så ved det hack tjekker den om sourceIndex eksistererer, hvis det gør, henter den sourceIndex fra det element der blev klikket på og lægger 1 til. Det betyder så, at vi får det næste element (det samme som nextSibling burde). Så den fejl omgås på den måde.
Den sidste ting er: li_elements = e_parent.getElementsByTagName('li');
Her vælger IE alle LI tags (også dem der ligger i de underliggende UL elementer). For at undgå det tjekkede jeg, at de LI'er der skulle være grønne rent faktisk var en del af samme parent element som den LI der blev klikket på. Håndteret sådan her: e_parent = e.parentNode; if (li_elements[j].parentNode == e_parent) { // lav grøn }
Det blev en lang smøre, håber du kan få lidt ud af det :)
Jeg fandt en lille fejl i din kode. Når man klikker på [Test a.2.1] i IE7 farves parent røde. Den har jeg rettet og i forhold til mit behov virker nedenstående. Dog opstår der en script fejl, hvis det li-element man klikker på, er det sidste. Det sker når man klikker på [Test a.2.1], [Test a.3], [Test c.1] og [Test d]. Fejlen opstår ved brugen af nextSibling, men ved ikke hvordan jeg rette det så fejlen ikke opstår.
Men som sagt virker koden efter hensigten nu :)
<html> <head> <script> var myTime = null;
function changeStatus(e) { myTime = null; var myDiv = document.getElementById('myTest'); var myUls = myDiv.getElementsByTagName('ul');
// farver alle ul-elementer røde for(var i = 0; i < myUls.length; i++) { myUls[i].style.background = 'red'; }
// hvis næste element er af typen ul, farves den grønt var myNextSibling = e.nextSibling; if (myNextSibling != null) { // sikrer at myNextSibling er et element og ikke et linjeskift eller lignende. while (myNextSibling != null && myNextSibling.nodeType !=1) { myNextSibling = myNextSibling.nextSibling; }
// vi skal lige have IE med også if (e.sourceIndex != undefined) { ie_element = document.all[e.sourceIndex + 1]; if (ie_element.nodeName == 'UL') { myNextSibling = ie_element; } } }
// hvis næste element er af typen ul, farves den grønt var myNextSibling = e.nextSibling; if (myNextSibling != null) { // sikrer at myNextSibling er et element og ikke et linjeskift eller lignende. while (myNextSibling != null && myNextSibling.nodeType !=1) { myNextSibling = myNextSibling.nextSibling; }
myNextSibling.style.background = 'green'; } // vi skal lige have IE med if (e.sourceIndex != undefined) { ie_element = document.all[e.sourceIndex + 1]; if (ie_element.nodeName == 'UL') { //myNextSibling = ie_element; ie_element.style.background = 'green'; } } }
// for IE's skyld function loadChange(e) { if(myTime == null) { myTime = setTimeout(function() {changeStatus(e)}, 10); } } </script>
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.