2017-09-29 1 views
0

hinzufügen Ich habe eine UL mit einigen li ist innen. Ich möchte nach dem Zufallsprinzip eine li auswählen und fügen Sie eine .active Klasse für 1 Sekunde, dann entfernen Sie .active Klasse und wählen Sie zufällig eine nächste li.Wie Klasse zufällig Element in reinem Javascript

Ich versuche, dies ohne die Verwendung von setInterval oder Timeout zu tun, also habe ich versucht mit requestAnimationFrame, obwohl ich denke, meine Logik mit Javascript ist nicht ganz richtig bei der Randomisierung.

Derzeit habe ich es funktioniert, aber es wählt die gleiche li jedes Mal, wenn die Funktion erneut aufgerufen wird.

<ul> 
    <li class="light active"></li> 
    <li class="light"></li> 
    <li class="light"></li> 
    <li class="light"></li> 
    <li class="light"></li> 
</ul> 

Javascript

(function() { 

var lights = document.getElementsByClassName("light"); 
var random = Math.floor(Math.random() * (lights.length - 1)) + 0; 
var randomLight = lights[random]; 

function repeatOften() { 
    randomLight.classList += randomLight.classList ? ' active' : ' light'; 
    requestAnimationFrame(repeatOften); 
} 
requestAnimationFrame(repeatOften); 

})(); 

ist hier ein Stift: https://codepen.io/H0BB5/pen/PJjapX?editors=0010

Vielen Dank im Voraus!

+0

Und warum genau versuchen Sie, 'setInterval()' zu vermeiden? –

+0

Sie starten nie Ihre 'repeatOften()' Funktion. Es wird also nicht immer die 'active' Klasse gesetzt, sondern nur für den ersten Fall. – Adjit

+0

@AlexeySoshin Vermeiden Sie Layout-Thrashing, inkonsistente Verzögerungsintervalle und wenn der Benutzer Tabs ändert, beeinflusst dies das Timing.Von was ich gelesen habe requestAnimationFrame ist der Weg zu gehen und ich versuche, mich selbst zu machen :) – h0bb5

Antwort

0

Die richtige Wahl, um eine Funktion in einer mehr oder weniger bekannten Zeit in der Zukunft auszuführen, ist setTimeout. requestAnimationFrame ist für etwas gedacht, das so oft wie möglich ausgeführt werden sollte, ohne die Renderschleife zu unterbrechen, etwa 60 Mal pro Sekunde (aka "bei 60 fps").

In Ihrem Fall haben Sie eine relativ langsame Update-Rate von einmal pro Sekunde, so setTimeout ist nicht schmerzhaft.

Sie möchten wahrscheinlich zwei Elemente im Auge behalten: Dasjenige, das Sie ändern, und das, das Sie zuvor geändert haben, damit Sie es zurücksetzen können.

Auch classList.toggle ist praktisch, da es eine Klasse hinzufügt oder entfernt, basierend darauf, ob sie bereits vorhanden ist oder nicht.

(function() { 
    var lights = document.getElementsByClassName("light"); 
    var previousLight = null; 

    function repeatOften() { 
    if (previousLight) previousLight.classList.toggle('active') 

    var random = Math.floor(Math.random() * (lights.length - 1)) + 0; 
    var randomLight = lights[random]; 
    randomLight.classList.toggle(randomLight); 
    previousLight = randomLight; 
    setTimeout(repeatOften, 1000); 
    } 

    setTimeout(repeatOften, 1000); 
})(); 

Here ist der aktualisierte (und leicht veränderte) Stift.

+1

Gewählt korrekt, da es die Best-Practice-Lösung für meine Frage ist, obwohl es RequestAnimationFrame nicht verwendet. Die Antwort von sven ist, was ich gesucht habe, ist aber nicht die richtige Lösung für diese Art von Problem. – h0bb5

0

Sie müssen jedes Mal, wenn die Funktion ausgeführt wird, aktualisieren, welches Licht blinkt. Um jede Sekunde ein anderes Licht zu wechseln, überprüfen Sie, ob die Animationsrahmenzeit eine Sekunde war.

(function repeatOften(ts) { 
 
    if (ts % 1000 < 10) { 
 
    document.getElementsByClassName("active")[0].classList.remove('active'); 
 
    var lights = document.getElementsByClassName("light"); 
 
    lights[Math.floor(Math.random() * lights.length)].classList.add('active'); 
 
    } 
 
    requestAnimationFrame(repeatOften); 
 
})();
li { 
 
    background: 1px black 
 
} 
 

 
li.active { 
 
    animation: blink 1s ease-in-out infinite; 
 
} 
 

 
@keyframes blink { 
 
    50% { 
 
    opacity: 0; 
 
    } 
 
}
<ul> 
 
    <li class="light active"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
</ul>

0

Ich versuche, diese von setInterval oder Timeout ohne den Einsatz zu tun

Sie animationend Ereignis verwenden können gleiche Funktion aufzurufen, wenn aktuelle CSS-Animation abgeschlossen

function fn() { 
 
    var lights = document.querySelectorAll(".light"); 
 
    var random = Math.floor(Math.random() * lights.length); 
 
    var randomLight = lights[random]; 
 
    repeatOften(randomLight) 
 
}; 
 

 
function repeatOften(randomLight) { 
 
    randomLight.className = "light active"; 
 
    randomLight.addEventListener("animationend", blink) 
 
} 
 

 
function blink() { 
 
    this.className = "light"; 
 
    this.removeEventListener("animationend", blink); 
 
    fn(); 
 
} 
 

 
// handle first `li` 
 
document.querySelector(".light.active") 
 
.addEventListener("animationend", blink)
.light.active { 
 
    animation: blink 1s ease-in-out; 
 
} 
 

 
@keyframes blink { 
 
    50% { 
 
    opacity: 0; 
 
    } 
 
}
<ul> 
 
    <li class="light active"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
    <li class="light"></li> 
 
</ul>

Verwandte Themen