2016-10-01 3 views
2

Der Versuch, einen sehr einfachen Javascript-Countdown zu erstellen. Wenn die Registerkarte jedoch inaktiv ist, beginnt der Countdown zu verzögern und enthält eine falsche Anzahl.Countdown-Timer 'Verzögerungen' wenn Registerkarte inaktiv ist?

Siehe hier jsfiddle zum Beispiel: https://jsfiddle.net/gbx4ftcn/

function initTimer(t) { 

    var self = this, 
    timerEl = document.querySelector('.timer'), 
    minutesGroupEl = timerEl.querySelector('.minutes-group'), 
    secondsGroupEl = timerEl.querySelector('.seconds-group'), 

    minutesGroup = { 
     firstNum: minutesGroupEl.querySelector('.first'), 
     secondNum: minutesGroupEl.querySelector('.second') 
    }, 

    secondsGroup = { 
     firstNum: secondsGroupEl.querySelector('.first'), 
     secondNum: secondsGroupEl.querySelector('.second') 
    }; 

    var time = { 
    min: t.split(':')[0], 
    sec: t.split(':')[1] 
    }; 

    var timeNumbers; 

    function updateTimer() { 

    var timestr; 
    var date = new Date(); 

    date.setHours(0); 
    date.setMinutes(time.min); 
    date.setSeconds(time.sec); 

    var newDate = new Date(date.valueOf() - 1000); 
    var temp = newDate.toTimeString().split(" "); 
    var tempsplit = temp[0].split(':'); 

    time.min = tempsplit[1]; 
    time.sec = tempsplit[2]; 

    timestr = time.min + time.sec; 
    timeNumbers = timestr.split(''); 
    updateTimerDisplay(timeNumbers); 

    if (timestr === '0000') 
     countdownFinished(); 

    if (timestr != '0000') 
     setTimeout(updateTimer, 1000); 

    } 

    function animateNum(group, arrayValue) { 

    TweenMax.killTweensOf(group.querySelector('.number-grp-wrp')); 
    TweenMax.to(group.querySelector('.number-grp-wrp'), 1, { 
     y: -group.querySelector('.num-' + arrayValue).offsetTop 
    }); 

    } 

    setTimeout(updateTimer, 1000); 

} 

Ich bin nicht sicher, ob das Problem mit der Animation liegt, oder mit dem JS-Code selbst.

Zur Verdeutlichung: Ich möchte, dass der Countdown fortgesetzt wird, wenn die Registerkarte inaktiv ist, oder um "mit sich selbst aufzuholen", wenn die Registerkarte wieder in den Fokus kommt.

Ich weiß, dass setTimeout und setInterval Probleme mit inaktiven Tabs verursachen können, aber ich bin mir nicht ganz sicher, wie Sie das beheben können.

Jede Hilfe wäre sehr willkommen!

+0

Bitte entfernen Sie jeglichen Code, der für das spezifische Problem nicht relevant ist. – charlietfl

+0

Mögliches Duplikat von [Warum verzögert sich JavaScript setTimeout in einem anderen Tab?] (Http: // stackoverflow.com/questions/19328140/why-does-javascript-settimeout-lag-wenn-in-einemanderen-tab) –

+1

hinweis: endzeit speichern als datum und immer berechnen basierend auf unterschied zwischen jetzt und ende – charlietfl

Antwort

2

Dazu können Sie die HTML5 Visibility API verwenden, um zu erkennen, ob die Browser-Registerkarte aktiv ist oder nicht. Verwenden Sie das regelmäßige Binden von Ereignishandlern für Fokus und Unschärfe für das Browserfenster.

Grundsätzlich Sie pause() die Zeitleiste, wenn Sie aus der Registerkarte verwischen, und dann play(), wenn Sie die Registerkarte refocus geben. Beispiel hierfür in Aktion:

http://codepen.io/jonathan/pen/sxgJl

// Set the name of the hidden property and the change event for visibility 
var hidden, visibilityChange; 
if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support 
    hidden = "hidden"; 
    visibilityChange = "visibilitychange"; 
} else if (typeof document.mozHidden !== "undefined") { 
    hidden = "mozHidden"; 
    visibilityChange = "mozvisibilitychange"; 
} else if (typeof document.msHidden !== "undefined") { 
    hidden = "msHidden"; 
    visibilityChange = "msvisibilitychange"; 
} else if (typeof document.webkitHidden !== "undefined") { 
    hidden = "webkitHidden"; 
    visibilityChange = "webkitvisibilitychange"; 
} 

// If the page is hidden, pause the video; 
// if the page is shown, play the video 
function handleVisibilityChange() { 
    if (document[hidden]) { 
     tl.pause(); 
    } else { 
     tl.play(); 
    } 
} 

// Warn if the browser doesn't support addEventListener or the Page Visibility API 
if (typeof document.addEventListener === "undefined" || typeof document[hidden] === "undefined") { 
    // do nothing or throw error via alert() 
    alert("This demo requires a browser, such as Google Chrome or Firefox, that supports the Page Visibility API."); 
} else { 
    // Handle page visibility change 
    // Pause timeline 
    tl.pause(); 
} 

HTML5 Sichtbarkeit Docs:

https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API

In Bezug auf GreenSock Forum Thema:

http://forums.greensock.com/topic/9059-cross-browser-to-detect-tab-or-window-is-active-so-animations-stay-in-sync-using-html5-visibility-api/

Auch in GSAP das Äquivalent für SetTimeout() ist delayedCall()

bietet eine einfache Möglichkeit, eine Funktion nach einer bestimmten Zeit (oder Frames) zu nennen. Sie können optional auch eine beliebige Anzahl von Parametern an die Funktion übergeben.

GSAP delayedCall(): http://greensock.com/docs/#/HTML5/GSAP/TweenMax/delayedCall/

//calls myFunction after 1 second and passes 2 parameters: 
TweenMax.delayedCall(1, myFunction, ["param1", "param2"]); 

function myFunction(param1, param2) { 
    //do stuff 
} 

Ich hoffe, das hilft!

0

vor allem, ich muss erwähnen, dass diese Countdown-Animation ist wirklich hervorragend und elegant sehr geehrter Herr!

nun auf die Antworten gut ... getan: wie in vielen Artikeln erwähnt, und hier ist einer von ihnen:

setInterval (func, Verzögerung) bietet keine Garantie für eine gegebene Verzögerung zwischen Hinrichtungen. Es gibt Fälle, in denen die tatsächliche Verzögerung mehr oder weniger als gegeben ist. In der Tat garantiert es nicht, dass es überhaupt eine Verzögerung gibt.

Quelle: http://javascript.info/tutorial/settimeout-setinterval
und ..

Die meisten Browser gelten Leistungsverbesserungen durch die Priorität mehrerer Aufgaben auf inaktiven Tabs zu reduzieren oder sogar einige Teile der Seite , die nicht auf dem Bildschirm sind . Manchmal wirken sich diese Verbesserungen auch auf die Ausführung von Javascript-Intervallen mit aus.

Quelle: How can I make setInterval also work when a tab is inactive in Chrome?

wie Sie sehen können, erwähnt sie, dass setInterval nicht eine gegebene Verzögerung zwischen Ausführungen garantiert selbst wenn die Registerkarte aktiv ist, und lässt nur davon ausgehen, dass setTimeout (die, die Sie verwendet) ist auch das gleiche, weil sie relativ ist "das gleiche"

so was ist die Lösung für dieses Problem?
gut, was man eigentlich tun, ist Check wie oft hat zwischen dem Ereignisse tatsächlich abgelaufen ist, so etwas wie dies Codepen

EDIT: wie Sie angefordert haben, ist hier ein fiddle Ihren Countdown mit dem Update und ich habe //commented über die Änderungen, die ich an der Geige gemacht habe, also würde es hoffentlich leichter für Sie zu verstehen machen. Wenn Sie also den Countdown mit einem anderen Timer gekoppelt haben (z. B. mit dem Timer Ihres Telefons), sollten Sie das gleiche Ergebnis erhalten, auch wenn die Registerkarte inaktiv ist oder die Bildrate langsamer wird.

, wenn Sie meine Antwort genossen haben beachten Sie bitte als „die Antwort“ markieren oder zumindest abstimmen;)

+0

Danke für Ihre freundlichen Worte! Das ist super interessant. Weißt du, wo ich das in einem Skript wie meinem implementieren würde? Ich bin ziemlich neu für JS! –

+0

Das ist super hilfreich, nochmals danke! Obwohl es nicht immer funktioniert. Manchmal erreicht der Timer 0000, läutet und zeigt die Reload-Taste an, wie es sein soll. Ein anderes Mal klingelt es nicht und läuft ab 60:00 herunter. –

+0

Umm es tut mir wirklich leid, aber nachdem ich die Geige etwa 5 Mal probiert habe, sehe ich nicht den Fehler, den du beschreibst. Wenn Sie mit meiner Antwort zufrieden sind, markieren Sie diese bitte als "Antwort", indem Sie auf das Häkchen neben meiner Antwort klicken! es würde wirklich geschätzt werden .. –

0

Der einfachste Weg, um den Timer zu gewährleisten bleibt richtig, wenn ein Benutzer auf die Registerkarte abfährt und dann kehrt ist, Sitzungsspeicher zu verwenden - um die ursprüngliche Anfangszeit zu speichern:

auf dem ersten Laden - das lokale gegenwärtige datetime erhalten und in Sitzungsspeicher speichern (beachten Sie, dass nur eine Zeichenkette annehmen wird - also müssen Sie den Wert und dann parsen Sie es beim Abruf wieder aus).

Wenn die Registerkarte den Fokus verliert, wird die eingestellte Startzeit weiterhin als StartTime in ss gespeichert. Wenn die Registerkarte den Fokus wiedererlangt - eine Funktion haben, die die neue aktuelle Datetime erhält, die gespeicherte Datetime aus dem Sessionspeicher holt und die Differenz berechnet. Dann kann der Timer auf die neue reduzierte Zeit aktualisiert werden.

ZB wenn es 10:00 Uhr auf Seite laden - setzen Sie die StartTime in ss. Dann verbringt der Benutzer eine Minute auf der Website und geht für 5 Minuten außer Haus. Nach der Rückkehr - der oben beschriebene Prozess wird die aktuelle Zeit ist 10:06 und bestimmen, dass es 6 Minuten später als die Startzeit, so kann der Timer als solcher aktualisieren.

Dies vermeidet die Notwendigkeit von Intervallen und Timern usw. Sie können die Spezifität bei Bedarf auf ms heruntersetzen. Und auch - ich mag deine Geige auch.

Verwandte Themen