TextTrackList onchange событие не работает в IE и Edge
Событие TextTrackList.onchange не работает вIE иEdge . В Chrome и FireFox это работает нормально.
Есть ли какая-либо альтернатива, которую я могу использовать? Я искал доступные события , но не нашел ни одного.
Или как я могу создать обходной путь? Так он работает среди всех браузеров?
Https://www.javascripture.com/TextTrackList
var video = document.getElementById('video');
video.textTracks.addEventListener('change', function () {
console.log("TextTracks change event fired!");
});video {
max-width: 400px;
max-height: 400px;
}<video controls id="video">
<source src="https://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_30mb.mp4" type="video/mp4" />
<track label="Caption #1" kind="subtitles" srclang="nl" src="path/to/caption1.vtt">
<track label="Caption #2" kind="subtitles" srclang="en" src="path/to/caption2.vtt">
<track label="Caption #3" kind="subtitles" srclang="de" src="path/to/caption3.vtt">
</video> 2 ответов:
Возможно, Вам удастся создать своего рода полифилл.
Во-первых, чтобы определить, поддерживаем ли мы событие или нет, мы можем проверить наличие
('onchange' in window.TextTrackList). Таким образом, мы можем интегрировать наш несовершенный полифилл условно и оставить правильные реализации неизменными.Тогда мы можем перебирать каждый x-раз по текстовым дорожкам нашего Texttracklist'а, чтобы найти, какая из них активна, она должна быть той, у которой
modeустановлено значение"showing".Теперь нам просто нужно сохранить предыдущий активный трек и проверьте, совпадает ли текущий. В противном случае, увольте событие.
Таким образом, простая реализация может быть
// in an outer scope // textTracks is our TextTrackList object var active = getActive(); // start polling poll(); function poll() { // schedule next check in a frame requestAnimationFrame(poll); var current = getActive(); if (current !== active) { active = current; // update the active one // dispatchEvent is not supported on TextTrackList in IE... onchange({ target: textTracks }); } } function getActive() { for (var i = 0; i < textTracks.length; i++) { if (textTracks[i].mode === 'showing') { return textTracks[i]; } } }Но чтобы реализовать лучший полифилл, мы захотим переопределить оригинал
addEventListener,removeEventListenerиonchangeсвойства прототипа TextTrackList.Вот примерная реализация, которая не будет заботиться о третьем параме [add/remove] EventListener.
(function() { /* Tries to implement an 'change' Event on TextTrackList Objects when not implemented */ if (window.TextTrackList && !('onchange' in window.TextTrackList.prototype)) { var textTracksLists = [], // we will store all the TextTrackLists instances polling = false; // and run only one polling loop var proto = TextTrackList.prototype, original_addEvent = proto.addEventListener, original_removeEvent = proto.removeEventListener; var onchange = { get: getonchange, set: setonchange }; Object.defineProperty(proto, 'onchange', onchange); Object.defineProperty(proto, 'addEventListener', fnGetter(addListener)); Object.defineProperty(proto, 'removeEventListener', fnGetter(removeListener)); function fnGetter(fn) { return { get: function() { return fn; } }; } /* When we add a new EventListener, we attach a new object on our instance This object set as '._fakeevent' will hold informations about the current EventListeners the current onchange handler the parent <video> element if any the current activeTrack */ function initFakeEvent(instance) { // first try to grab the video element from where we were generated // this is useful to not run useless tests when the video is detached var vid_elems = document.querySelectorAll('video'), vid_elem = null; for (var i = 0; i < vid_elems.length; i++) { if (vid_elems[i].textTracks === instance) { vid_elem = vid_elems[i]; break; } } textTracksLists.push(instance); instance._fakeevent = { parentElement: vid_elem, listeners: { change: [] } } if (!polling) { // if we are the first instance being initialised polling = true; requestAnimationFrame(poll); // start the checks } return instance._fakeevent; } function getonchange() { var fakeevent = this._fakeevent; if (!fakeevent || typeof fakeevent !== 'object') { return null; } return fakeevent.onchange || null; } function setonchange(fn) { var fakeevent = this._fakeevent; if (!fakeevent) { fakeevent = initFakeEvent(this); } if (fn === null) fakeevent.onchange = null; if (typeof fn !== 'function') return fn; return fakeevent.onchange = fn; } function addListener(type, fn, options) { if (type !== 'change') { // we only handle change for now return original_addEvent.bind(this)(type, fn, options); } if (!fn || typeof fn !== 'object' && typeof fn !== 'function') { throw new TypeError('Argument 2 of EventTarget.addEventListener is not an object.'); } var fakeevent = this._fakeevent; if (!fakeevent) { fakeevent = initFakeEvent(this); } if (typeof fn === 'object') { if (typeof fn.handleEvent === 'function') { fn = fn.handleEvent; } else return; } // we don't handle options yet... if (fakeevent.listeners[type].indexOf(fn) < 0) { fakeevent.listeners[type].push(fn); } } function removeListener(type, fn, options) { if (type !== 'change') { // we only handle change for now return original_removeEvent.call(this, arguments); } var fakeevent = this._fakeevent; if (!fakeevent || !fn || typeof fn !== 'object' && typeof fn !== 'function') { return } if (typeof fn === 'object') { if (typeof fn.handleEvent === 'function') { fn = fn.handleEvent; } else return; } // we don't handle options yet... var index = fakeevent.listeners[type].indexOf(fn); if (index > -1) { fakeevent.listeners[type].splice(index, 1); } } function poll() { requestAnimationFrame(poll); textTracksLists.forEach(check); } function check(instance) { var fakeevent = instance._fakeevent; // if the parent vid not in screen, we probably have not changed if (fakeevent.parentElement && !fakeevent.parentElement.parentElement) { return; } // get the current active track var current = getActiveTrack(instance); // has changed if (current !== fakeevent.active) { if (instance.onchange) { try { instance.onchange({ type: 'change', target: instance }); } catch (e) {} } fakeevent.listeners.change.forEach(call, this); } fakeevent.active = current; } function getActiveTrack(textTracks) { for (var i = 0; i < textTracks.length; i++) { if (textTracks[i].mode === 'showing') { return textTracks[i]; } } return null; } function call(fn) { fn({ type: 'change', target: this }); } } })(); var video = document.getElementById('video'); video.textTracks.onchange = function ontrackchange(e) { console.log('changed'); };video { max-width: 400px; max-height: 400px; }<video controls id="video"> <source src="https://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_30mb.mp4" type="video/mp4" /> <track label="Caption #1" kind="subtitles" srclang="nl" src="path/to/caption1.vtt"> <track label="Caption #2" kind="subtitles" srclang="en" src="path/to/caption2.vtt"> <track label="Caption #3" kind="subtitles" srclang="de" src="path/to/caption3.vtt"> </video>
Вы правы, это проблема с IE и Edge. То, что вы можете сделать, это прослушать событие на треке загрузки. Просто обратите внимание, что трек должен быть в том же домене, иначе вы получите тихую ошибку (CURS), и список событий не будет перечислять событие.
Я создал кодовую панель, чтобы вы могли попробовать ее https://codepen.io/shahar-polak/project/live/AnVpEw/
Примечание: код вызовет одно событие в IE и Edge и два события в Chrome и Firefox. Убедитесь, что вы проверяете наличие браузера клиента перед использованием в рабочей среде.
const video = document.getElementById('video'); const tracks = Array.from(document.querySelectorAll('track')); video.textTracks.addEventListener('change', function() { console.log('TextTracks change event fired!'); }); // For IE and Edge tracks.forEach((track) => { track.addEventListener("load", function() { console.log('change track'); }, false); })video { max-width: 400px; max-height: 400px; }<video controls id="video" > <source src="https://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_30mb.mp4" type="video/mp4"/> <track label="Caption #1" kind="subtitles" srclang="nl" src="./en.vtt"> <track label="Caption #2" kind="subtitles" srclang="en" src="./en.vtt"> <track label="Caption #3" kind="subtitles" srclang="de" src="https://iandevlin.com/html5/dynamic-track/captions/sintel-en.vtt"> </video>
Comments