Vimeo通过iFrame在Firefox上窃取鼠标滚轮事件

8
我在这里制作了一个示例: http://jsbin.com/pokahec/edit?html,output
// creates a global "addWheelListener" method
// example: addWheelListener( elem, function( e ) { console.log( e.deltaY ); e.preventDefault(); } );
(function(window,document) {

var prefix = "", _addEventListener, onwheel, support;

// detect event model
if ( window.addEventListener ) {
    _addEventListener = "addEventListener";
} else {
    _addEventListener = "attachEvent";
    prefix = "on";
}

// detect available wheel event
support = "onwheel" in document.createElement("div") ? "wheel" : // Modern browsers support "wheel"
          document.onmousewheel !== undefined ? "mousewheel" : // Webkit and IE support at least "mousewheel"
          "DOMMouseScroll"; // let's assume that remaining browsers are older Firefox

window.addWheelListener = function( elem, callback, useCapture ) {
    _addWheelListener( elem, support, callback, useCapture );

    // handle MozMousePixelScroll in older Firefox
    if( support == "DOMMouseScroll" ) {
        _addWheelListener( elem, "MozMousePixelScroll", callback, useCapture );
    }
};

function _addWheelListener( elem, eventName, callback, useCapture ) {
    elem[ _addEventListener ]( prefix + eventName, support == "wheel" ? callback : function( originalEvent ) {
        !originalEvent && ( originalEvent = window.event );

        // create a normalized event object
        var event = {
            // keep a ref to the original event object
            originalEvent: originalEvent,
            target: originalEvent.target || originalEvent.srcElement,
            type: "wheel",
            deltaMode: originalEvent.type == "MozMousePixelScroll" ? 0 : 1,
            deltaX: 0,
            deltaZ: 0,
            preventDefault: function() {
                originalEvent.preventDefault ?
                    originalEvent.preventDefault() :
                    originalEvent.returnValue = false;
            }
        };

        // calculate deltaY (and deltaX) according to the event
        if ( support == "mousewheel" ) {
            event.deltaY = - 1/40 * originalEvent.wheelDelta;
            // Webkit also support wheelDeltaX
            originalEvent.wheelDeltaX && ( event.deltaX = - 1/40 * originalEvent.wheelDeltaX );
        } else {
            event.deltaY = originalEvent.detail;
        }

        // it's time to fire the callback
        return callback( event );

    }, useCapture || false );
}

})(window,document);

在 Firefox 测试时,可以检测到滚动事件被触发,除了当滚动到 Vimeo iframe(和我猜任何 iFrame)时。

是否有解决方法来触发 iframe 上的事件?

PS- 我想在自定义滚动条中使用这个

3个回答

7
这基本上是有意设计的。您的代码应完全不知道用户在IFRAME内部做了什么(尤其是来自YouTube等不同源的IFRAME - 这是Web安全体系结构的一部分,由同源策略规定。)
即使在跨源情况下,浏览器也可以选择让滚动影响框架的祖先,如果框架本身不滚动。此滚动应在顶部文档上没有任何事件触发的情况下发生 - 请参见Chrome的行为,如果您滚动到此IFRAME的底部并继续滚动:http://jsfiddle.net/8cj0dofx/1/HTML:
<iframe src="data:text/html,<body style='background:grey;height:550px'>Hello" seamless></iframe>
<div style="height:100px">Hello</div>

JS:

document.addEventListener('DOMMouseScroll', function(e){
    document.getElementsByTagName('div')[0].firstChild.data += ' ' + e.type
});

document.addEventListener('mousewheel', function(e){
    document.getElementsByTagName('div')[0].firstChild.data += ' ' + e.type
});

当你滚动到IFRAME的末尾时,你会发现主文档将会滚动,但是直到鼠标移动到父文档上方之前,不会触发任何事件。

那么没有任何漏洞吗? - digitalzoomstudio
1
嗯,我想你可以在IFRAME上面放一个透明的DIV - 但是你的访问者可能会失去实际播放/暂停视频的能力。 - hallvors
此外,如果在IFRAME上添加“scrolling=no”属性,则浏览器将不会单独滚动IFRAME内容。不确定这是否有助于您的用例 - 当悬停IFRAME时,外部页面将滚动,但在IFRAME移开之前,您将不会收到任何事件。 - hallvors
1
是的,pointer-events:none 在 iframe 上同样有效,但基本上我们还需要播放功能 :D - digitalzoomstudio
1
与此同时,我已经改变了我的想法,不确定它是一个错误还是一个特性...所以我重新打开了https://bugzilla.mozilla.org/show_bug.cgi?id=1084121。 - hallvors
显示剩余4条评论

4
看起来这是Firefox的一个bug:https://bugzilla.mozilla.org/show_bug.cgi?id=1084121。因此可能没有一种直接的方法来处理它。但是由于即使未被派发,该操作也会产生影响,因此可以使用一个解决方法。虽然它可能不适用于每种情况,但它应该覆盖很多情况。
您可以检测滚动而不是检测鼠标滚轮事件,并使用一个开关来检测鼠标是否点击。如果窗口滚动并且鼠标没有被点击,那么它很可能来自mousewheel。在触发它的脚本中将处理其他情况变得容易。
唯一无法处理的情况是窗口无法再次滚动,那么您将无法获得事件。代码如下:
var mouseDown = false;

function handle_wheel() {
    if (!mouseDown) {
        document.getElementById("debug-textarea").value = document.getElementById("debug-textarea").value + ' wheel';
    } else {
        document.getElementById("debug-textarea").value = document.getElementById("debug-textarea").value + ' scroll';
    }
}

window.onscroll = handle_wheel;
window.onmousedown = function () {
    mouseDown = true;
}
window.onmouseup = function () {
    mouseDown = false;
}

http://jsfiddle.net/wu9y6yua/4/


很好,但这并没有帮助我 - 首先,我无法检测到滚轮滚动。 - digitalzoomstudio
第二个目的是自定义滚动条,因为主体溢出被隐藏,所以实际上不会滚动(因此没有滚动事件)-请检查新示例。 - digitalzoomstudio

0

我遇到了同样的问题,但是涉及到滚动缩放功能。

由于无法直接捕获鼠标滚轮事件,除非使用一些技巧,我认为最好的选择是在iframe上方放置一个透明的div,并在单击时添加&autoplay=1参数到vimeo/youtube的URL中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接