2012-04-19 2 views
18

Ich baue ein jQuery-Plugin für die Verwaltung von HTML5-Videos. Ich versuche das canplay zu erfassen und Events zu canceln. In Chrome wird das Ereignis ohne Probleme ausgelöst. In Firefox wird es manchmal ausgelöst, manchmal nicht.Die Ereignisse canplay/caneplaythrough für ein HTML5-Video werden in Firefox nicht aufgerufen. Warum?

Ich vereinfacht meinen Code ein wenig hier:

$('#my_video').on('canplay canplaythrough', function(){ 
    console.log('canplay event fired'); 
}); 

ich auch mit dem nativen Javascript .addEventListener versucht() und es funktioniert nicht.

Irgendeine Idee, warum das Ereignis nicht auf Firefox aufgerufen wird und wie man das repariert?

HINWEIS: Bitte sagen Sie mir nicht, eines der bereits verfügbaren Plugins wie jplayer und video-js zu verwenden, ich weiß, dass sie existieren und gut funktionieren, aber ich muss eine Inhouse-Lösung aufbauen.

Antwort

36

Das Problem ist, dass Ihr video Element das Ereignis canplaythrough ausgelöst hat, bevor Sie den Ereignishandler registriert haben.

Wie Sie in Ihrer eigenen Antwort darauf hingewiesen haben, können Sie Ihre Skripte in die <head> setzen, aber das ist schlecht für Ihre Seitenleistung.

Eine bessere Möglichkeit, Ihr Problem zu beheben, ist das readystate Attribut zu überprüfen und Ihre Funktion manuell in diesem Fall ausführen:

var $video = $('video'), 
    videoElement = $video[0]; 

$video.on('canplaythrough', callback); 

// If the video is in the cache of the browser, 
// the 'canplaythrough' event might have been triggered 
// before we registered the event handler. 
if (videoElement.readyState > 3) { 
    callback(); 
} 
+0

Beste Antwort! Prüfe den Video-Ready-Status und füge den Ereignis-Listener hinzu, wenn readyState isn ' t '4' oder höher – peirix

+0

Erstaunliche Antwort: Das ist die eine Danke !!!! @Gabriel sollte man dies als die Antwort auf jeden Fall markieren – 30secondstosam

+0

Scripts nicht in den Kopf zu legen, ist schlecht für: Skripte schreiben und zeigen ein Mangel an Standards nicht zu verstehen: Verwenden Sie das "Defer" -Attribut, behalten Sie Skripte im Kopf und haben Sie immer noch die gleiche Leistung. – John

4

Auch wenn meine Frage keine Aufmerksamkeit überhaupt bekommen haben, ich denke, es ist eine gute Idee, eine Erklärung für die Menschen zu geben, die auf diese in die Zukunft stolpern ...

Das Problem ist wirklich seltsam: wenn Der jQuery-Kern ist in der Fußzeile enthalten, einige der Videoereignisse funktionieren nicht. Wenn der jQuery-Core im Kopf des Dokuments enthalten ist, werden alle Ereignisse korrekt aufgerufen.

Die Lösung besteht also darin, den jQuery-Kern in den HTML-Kopf aufzunehmen, auch wenn "Best Practices" für die Optimierung empfiehlt, alle Skripte am Ende des Körpers zu platzieren, um die Ladezeiten zu verkürzen.

+3

ich seinen eigentlich einen Rennen-Zustand Wette würde, und die Ereignisse 'canplay' und' caplaythrough' werden ausgelöst _before_ jQuery fügt die Ereignis-Listener an. EDIT: Habe gerade bemerkt, dass Clayton Gulick das Problem unten diskutiert hat. –

10

Der wahrscheinlichste Grund, warum Sie das sehen, hat wahrscheinlich mit Timing-Problemen zu tun. Sie haben in Ihrer akzeptierten Antwort angegeben, dass das Problem durch das Einfügen von jQuery in den Kopf und nicht in die Fußzeile gelöst wird. Dies sagt mir, dass das Problem das DOM-Parsing und die Skript-Ausführungsreihenfolge ist. Der wahrscheinlichste Grund ist, dass die Ereignisse "canplay" und "caplaythrough" ausgelöst wurden, bevor jquery und Ihr Seitenskript analysiert wurden und die Ereignishandler hinzugefügt wurden - aber nur manchmal, abhängig vom Netzwerkverkehr und Ladezeiten. Durch das Einfügen des Skripts in den Kopf erzwangen Sie, dass die Ereignisbindung vor dem Erstellen der DOM-Elemente erfolgte, und stellten so sicher, dass keine Ereignisse verpasst wurden.

Nebenbei sind die Leistungsvorteile des Puttens von Skriptelementen am Ende der Seite umstritten. Wenn Sie die Seitenleistung wirklich optimieren möchten, verwenden Sie etwas wie LABjs, um das Laden von parallelem Skript zu verwalten.

3

Ich denke auch, dass dies eine Wettlaufbedingung ist. Die Art, wie ich es geschafft habe, ist wie folgt:

Im HTML des Videoelements fügen Sie das Attribut preload = "metadata" hinzu - um die Metadaten des Videos vorab zu laden. Also:

<video id="myVideo" width="640" height="480" preload="metadata" /> 

Als nächste in der JS:

var $vid = $("#myVideo"); 
$vid.bind("canplaythrough", console.log("can play through full video")); 
$vid.get(0).load(); 

Diese die Nachricht für mich in Chrome angemeldet - nicht an anderer Stelle getestet.

2

Wenn erwarten Sie die Firefox das gesamte Audio zu laden, nachdem Sie load dann auslösen würde es tu das nicht. Es wird die loadstart feuern, aber nichts herunterladen. No progress Ereignisse werden ausgelöst. Und es wird tatsächlich keine Anfrage an diese Datei stellen. Sie können dieses Verhalten im Firebug sehen.

Firefox beginnt erst mit dem Laden der Datei, nachdem Sie 'play' ausgelöst haben.

Proof. Siehe Konsolenausgabe.

+0

tatsächlich wird dieses Verhalten erwartet und kann mit dem Preload-Attribut im Video gesteuert werden –

+0

@NamanGoel 'Das Preload-Attribut gibt an, ob und wie der Autor denkt dass die Audiodatei geladen werden soll, wenn die ** Seite geladen wird. 'Soweit ich das verstehen kann, hat' preload' nichts mit 'audio.load()' zu tun.Stattdessen ändert es das Verhalten des Browsers, wenn keine Aktion mit dem Audio ausgeführt wird. Wenn ich mich irre, verweisen Sie mich bitte auf die Dokumentation. Ist es möglich, den Ton beim Laden der Seite NICHT zu laden und stattdessen beim Laden von 'load()' vollständig zu laden? – Kolyunya

+0

Ich kann gerade keinen Link korrigieren. Aber von dem, was ich weiß, soll der Browser das Audio nicht laden, es sei denn, es hat den "preload" Attr. Einige Browser laden Audio/Video sowieso vor, um schnell zu erscheinen. –

0

Hinzufügen:

var video = $('video'); 
video.trigger('load'); 

Nach Zugabe des canplaythrough Ereignis-Listener es für mich auf Firefox und Safari behoben.

2

In meinem Fall wurde dies durch das preload Attribut für das Element bestimmt. Ich hatte es überhaupt nicht spezifiziert, also wählten verschiedene Browser verschiedene Dinge.

Sobald ich preload="auto" spezifizierte, funktionierte der on("canplay") Ereignishandler gut/wie erwartet.

0

Nach 1,5 Tagen versuchen verschiedene Ansätze von hier (in Vanille). Die Ereignisse "canplay" und "canplay through" mit addEventListner funktionieren in Edge nicht. Sie funktionieren gut in jedem anderen Browser. So landete ich mit einem Scheck von „ready-Zustand“ mit setTimout bis :-(. Nicht wirklich elegant, aber es funktioniert für mich.

Controller.prototype.backGroundControl = function() { 
var vid = document.querySelector('#bgvid'); 
var bgImg = document.querySelector('#bgimg'); 
_this = this; 

if (vid.readyState === 4){ 
    bgImg.style.opacity = "0" 
} else{ 
    setTimeout(function(){ 
     _this.backGroundControl(); 
    },500) 
} 

}