TextTrackList onchange事件在IE和Edge中不起作用 [英] TextTrackList onchange event not working in IE and Edge

查看:75
本文介绍了TextTrackList onchange事件在IE和Edge中不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

TextTrackList.onchange 事件在 IE Edge 中无效。在 Chrome FireFox 中,它运行正常。

The TextTrackList.onchange event is not working in IE and Edge. In Chrome and FireFox it works fine.

我可以使用其他替代品吗?我搜索了可用的事件但找不到任何内容。

Is there any alternative I can use? Ive searched through the available events but can't find any.

或者我该如何创建变通方法?它适用于所有浏览器吗?

Or how can I create a workaround? So it works amongst all browsers?

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>

推荐答案

您可以创建一种polyfill。

You might be able to create a kind of polyfill.

首先检测我们是否支持该事件,我们可以检查(window.TextTrackList中的'onchange')。所以我们可以有条件地整合我们不完美的polyfill并保持正确的实现不变。

First to detect if we support the event or not, we can check for ('onchange' in window.TextTrackList). So we can integrate our unperfect polyfill conditionally and leave the correct implementations unchanged.

然后,我们可以在TextTrackList的TextTracks上每隔x次迭代一次,以便找到哪一个是活动的,它应该是模式设置为显示的那个。

Then, we can iterate every x-time over our TextTrackList's TextTracks in order to find which one is the active one, it should be the one with its mode set to "showing".

现在,我们只需存储上一个活动曲目并检查当前曲目是否相同。否则,触发事件。

Now, we just have to store the previous active track and check if the current one is the same. Otherwise, fire the Event.

所以一个简单的实现可能是

So a simple implementation could be

// 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];
    }
  }
}

但要实现更好的polyfill ,我们将要覆盖原始 addEventListener removeEventListener onchange TextTrackList原型的属性。

But to implement a better polyfill, we will want to override the original addEventListener, removeEventListener and onchange properties of the TextTrackList prototype.

这是一个粗略的实现,它不会处理 [add / remove] EventListener的第三个参数

Here is a rough implementation, which will not take care of the third param of [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>

这篇关于TextTrackList onchange事件在IE和Edge中不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆