【问题标题】:Why don't audio and video events bubble?为什么音频和视频事件不冒泡?
【发布时间】:2012-07-02 17:57:08
【问题描述】:

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

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

【问题讨论】:

    标签: javascript html audio video dom-events


    【解决方案1】:

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

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

    您可以阅读更完整的事件冒泡历史here

    事件委托

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

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

    请注意,此事件不会冒泡,而是会沿 DOM 树向下移动,并且无法通过 stopPropagation 停止。

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

    $.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 上注册一个全局事件侦听器确实有意义,例如,它会捕获来自文档中任何媒体元素的事件。
    • 很遗憾,但可以理解。不幸的是,它确实使像 jQuery 的委托系统这样的“技巧”无法使用。 IE。您可以将一个 play 监听器附加到例如主体,并且只要任何<audio> 触发该事件,该函数就会被执行。 (这实际上是@Sergiu 的想法。)
    • 这不是我的问题 :) 我通常不会很快提供赏金,但不要担心。
    • 感谢您提供这个简洁的解决方案,正是我一直在寻找的东西!对于像我一样使用 rxjs' fromEvent 的任何人,您可以添加第三个参数来捕获子元素中的事件,如下所示:fromEvent(document, 'timeupdate', {capture: true})
    猜你喜欢
    • 2023-03-12
    • 2011-06-04
    • 2017-02-14
    • 1970-01-01
    • 2011-03-18
    • 1970-01-01
    • 2014-09-14
    相关资源
    最近更新 更多