为什么音频和视频事件不冒泡?

IT技术 javascript html audio video dom-events
2021-01-14 12:12:03

我想知道为什么我的一些 Javascript 无法工作,直到我发现音频事件没有在 DOM 树中冒泡,例如timeupdate-event。

是否有理由不让音频和视频标签的事件冒泡?

1个回答

事件冒泡之所以存在,是为了解决哪个元素是事件的预期目标的模棱两可的问题。那么,如果您单击一个 div,您的意思是单击该 div 还是它的父级?如果子级没有附加点击处理程序,则它会检查父级,依此类推。我相信你知道这是如何工作的。

音频事件不会冒泡的原因是因为它们对任何其他元素都没有意义。当您timeupdate在音频元素上触发 a 时,无论它是用于音频元素本身还是其父 div 都没有歧义,因此无需冒泡。

您可以在此处阅读更完整的事件冒泡历史

事件委托

通过利用事件的捕获阶段,事件委托仍然是可能的。只需添加 true 作为 addEventListener 的第三个参数,如下所示:

document.addEventListener('play', function(e){
    //e.target: audio/video element
}, true);

请注意,此事件不会冒泡,而是沿着 DOM 树向下移动,并且无法使用stopPropagation.

如果您想将其与 jQuery 的 .on/.off 方法一起使用(例如具有命名空间和其他 jQuery 事件扩展)。webshim 库中获取的以下函数应该会变得有用:

$.createEventCapturing = (function () {
    var special = $.event.special;
    return function (names) {
        if (!document.addEventListener) {
            return;
        }
        if (typeof names == 'string') {
            names = [names];
        }
        $.each(names, function (i, name) {
            var handler = function (e) {
                e = $.event.fix(e);

                return $.event.dispatch.call(this, e);
            };
            special[name] = special[name] || {};
            if (special[name].setup || special[name].teardown) {
                return;
            }
            $.extend(special[name], {
                setup: function () {
                    this.addEventListener(name, handler, true);
                },
                teardown: function () {
                    this.removeEventListener(name, handler, true);
                }
            });
        });
    };
})();

用法:

$.createEventCapturing(['play', 'pause']);

$(document).on('play', function(e){
    $('audio, video').not(e.target).each(function(){
        this.pause();
    });
});
虽然将媒体事件冒泡到其他类型的元素没有多大意义,但在 上注册全局事件侦听器确实有意义body,例如,它将捕获来自文档中任何媒体元素的事件。
2021-03-23 12:12:03
感谢您提供这个巧妙的解决方案,这正是我一直在努力寻找的!对于像我这样使用rxjs' fromEvent 的任何人,您可以添加第三个参数来捕获子元素中的事件,如下所示: fromEvent(document, 'timeupdate', {capture: true})
2021-03-25 12:12:03
这很遗憾,但可以理解。不幸的是,它确实使像 jQuery 的委托系统这样的“技巧”无法使用。即,您将一个play侦听器附加到例如主体上,并且该函数将在任何<audio>触发该事件时执行(这实际上是@Sergiu 的想法。)
2021-03-27 12:12:03
这不是我的问题 :) 我通常不会很快给予赏金,但别担心。
2021-03-27 12:12:03