当鼠标移动到一个iframe上时如何检测mousemove事件?

40

我有一个占据整个窗口(100%宽,100%高)的 iframe,需要主窗口能够检测到鼠标移动。

已经尝试在iframe上使用 onMouseMove 属性,但显然没有起作用。还尝试将 iframe 包装在 div 中,如下所示:

<div onmousemove="alert('justfortesting');"><iframe src="foo.bar"></iframe></div>

...但它没有起作用。有什么建议吗?


2
我不确定是否正确。已经过去多年了。我认为您需要在子页面(加载到框架中的页面)中捕获mouseover事件。 - d-_-b
12个回答

37

如果你的目标浏览器不是Opera 9或更低版本以及IE 9或更低版本,你可以使用CSS属性pointer-events: none

我发现忽略iframe是最好的方法。在onMouseDown事件中,我为iframe添加了一个带有这个属性的类,并在onMouseUp事件中删除该类。

对我来说效果非常好。


3
这是一个很好的解决方案,我相信这是最佳的选择。唯一的问题是目前IE浏览器还不支持pointer-event属性。http://caniuse.com/#search=pointer-events - Well Actually
4
有没有办法让这个功能继续工作,但iframe仍然是可交互的? - Ethan
13
唯一的问题是,如果将指针事件设置为 "none",则无法以任何方式与 iframe 进行交互,因此对于许多用例,这种方法不起作用。 - HastingsDirect
哇,我花了好几个小时才做完这个。没想到它竟然是那么简单的。非常感谢! - AryanJ-NYC

28

框架可以捕获鼠标事件,但是如果符合跨域政策,您可以将事件传输到父级作用域。以下是方法:

// This example assumes execution from the parent of the the iframe

function bubbleIframeMouseMove(iframe){
    // Save any previous onmousemove handler
    var existingOnMouseMove = iframe.contentWindow.onmousemove;

    // Attach a new onmousemove listener
    iframe.contentWindow.onmousemove = function(e){
        // Fire any existing onmousemove listener 
        if(existingOnMouseMove) existingOnMouseMove(e);

        // Create a new event for the this window
        var evt = document.createEvent("MouseEvents");

        // We'll need this to offset the mouse move appropriately
        var boundingClientRect = iframe.getBoundingClientRect();

        // Initialize the event, copying exiting event values
        // for the most part
        evt.initMouseEvent( 
            "mousemove", 
            true, // bubbles
            false, // not cancelable 
            window,
            e.detail,
            e.screenX,
            e.screenY, 
            e.clientX + boundingClientRect.left, 
            e.clientY + boundingClientRect.top, 
            e.ctrlKey, 
            e.altKey,
            e.shiftKey, 
            e.metaKey,
            e.button, 
            null // no related element
        );

        // Dispatch the mousemove event on the iframe element
        iframe.dispatchEvent(evt);
    };
}

// Get the iframe element we want to track mouse movements on
var myIframe = document.getElementById("myIframe");

// Run it through the function to setup bubbling
bubbleIframeMouseMove(myIframe);
你现在可以监听iframe元素或其任何父元素的mousemove事件 - 事件会像预期的那样冒泡。
这与现代浏览器兼容。如果您需要它与IE8及以下版本一起工作,您需要使用IE特定的替换方案createEventinitMouseEventdispatchEvent

请查看我最新的答案,了解有关弃用和如何处理它的更多信息。 - jeremy

17

我用过的另一种解决方法是,在鼠标按下时禁用iframe上的鼠标移动事件:

$('iframe').css('pointer-events', 'none');

然后,在鼠标抬起时重新启用iframe(s)上的鼠标移动事件:

$('iframe').css('pointer-events', 'auto');

我尝试过一些其他的方法,它们都可以工作,但这似乎是最简单的方法。

感谢:https://www.gyrocode.com/articles/how-to-detect-mousemove-event-over-iframe-element/


1
非常简单的解决方案对我很有效。值得一试。 - Johan Danforth

9

MouseEvent.initMouseEvent()现在已经被弃用,因此@Ozan的回答有些过时。作为他回答所提供内容的替代方案,我现在这样做:

var bubbleIframeMouseMove = function( iframe ){

    iframe.contentWindow.addEventListener('mousemove', function( event ) {
        var boundingClientRect = iframe.getBoundingClientRect();

        var evt = new CustomEvent( 'mousemove', {bubbles: true, cancelable: false})
        evt.clientX = event.clientX + boundingClientRect.left;
        evt.clientY = event.clientY + boundingClientRect.top;

        iframe.dispatchEvent( evt );

    });

};

当我设置clientXclientY时,您需要将内容窗口的事件中的任何信息传递给我们将要分派的事件(即,如果您需要传递像screenX/screenY这样的内容,请在此操作)。


1
一个不错的开始,但还不完整。并非所有相关数据都从捕获在iframe上的事件复制到生成的克隆体中。缺少的一件事是evt.buttons。看一下MouseEvent有多少个键,我几乎可以确定这不是唯一缺失的东西。通过将此解决方案与Jagi的解决方案并排运行,人们应该能够逐步“填补空白”。 - mathheadinclouds
也许可以使用Object.keys循环遍历所有键,进行标准克隆,然后仅手动处理那些发生更改的键,例如解决方案中的.clientX和.clientY。 - mathheadinclouds
我正在使用这个解决方案,并添加了一行,即evt.buttons = event.buttons,并且它对我所做的工作有效。对于其他用例,您可能需要复制更多,就像我说的那样。 - mathheadinclouds
1
IE浏览器没有CustomEvent,但有一个polyfill,详见https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent。 - mathheadinclouds
@dieterh 很高兴听到这个。 - jeremy

7
我曾经遇到类似的问题,我有一些div想要拖动到一个iFrame上。问题是,如果鼠标移动到div外面,进入iFrame时,mousemove事件就会丢失,div就停止拖动了。如果你想做这样的事情(而不仅仅是检测用户在iFrame上挥动鼠标),我在另一个问题线程中找到了一个建议,在我尝试它时效果很好。
在包含div和你想要拖动的东西的页面中,也包括像这样的一个

这对我来说完美地运作了。此外,我参考了一个相对简化的 div 叠加策略,来源于这篇帖子 - svarlamov

7

您的 iframe 中的页面是一个完整的文档。它将消耗所有事件,与其父文档没有直接联系。

您需要从子文档中的 JavaScript 捕获鼠标事件,然后以某种方式将其传递给父级。


5
有什么方法可以正确地传递鼠标坐标? - Rehno Lindeque

6
我发现一个相对简单的解决方案来解决我遇到的类似问题,即我想要调整 iframe 和它旁边的 div 的大小。当鼠标移到 iframe 上时,jQuery 将停止检测鼠标。
为了解决这个问题,我有一个 div 和 iframe 一起坐在同一个区域里,并具有相同的样式,除了 div 的 z-index 设置为 0,而 iframe 的 z-index 设置为 1。这使得在不调整大小时可以正常使用 iframe。
<div id="frameOverlay"></div>  
<iframe></iframe>

调整大小时,div的z-index会被设置为2,然后再设置为0。这意味着iframe仍然可见,但遮罩却阻挡了它,从而允许检测鼠标。

1
借鉴了你的想法。这是一个很好的答案,因为你不必担心从子级向父级冒泡事件。 - Lukus

5
在您的“父”框架中,选择您的“子”iframe并检测您感兴趣的事件,在您的情况下是mousemove
以下是在您的“父”框架中使用的代码示例。
document.getElementById('yourIFrameHere').contentDocument.addEventListener('mousemove', function (event) {
                console.log(, event.pageX, event.pageY, event.target.id);
            }.bind(this));

这段代码正确吗?因为我在使用iframe模式下没有获取到数据。 没有任何反应,也没有错误提示。 - Tiago

3
<script>
// dispatch events to the iframe from its container
$("body").on('click mouseup mousedown touchend touchstart touchmove mousewheel', function(e) {
    var doc = $("#targetFrame")[0].contentWindow.document,
        ev = doc.createEvent('Event');
    ev.initEvent(e.originalEvent.type, true, false);
    for (var key in e.originalEvent) {
        // we dont wanna clone target and we are not able to access "private members" of the cloned event.
        if (key[0] == key[0].toLowerCase() && $.inArray(key, ['__proto__', 'srcElement', 'target', 'toElement']) == -1) {
            ev[key] = e.originalEvent[key];
        }
    }
    doc.dispatchEvent(ev);
});
</script>
<body>
<iframe id="targetFrame" src="eventlistener.html"></iframe>
</body>

1

文档中的基本方法

var IE = document.all?true:false;

// If NS -- that is, !IE -- then set up for mouse capture
if (!IE) document.captureEvents(Event.MOUSEMOVE);

// Set-up to use getMouseXY function onMouseMove
document.onmousemove = getMouseXY;

// Temporary variables to hold mouse x-y pos.s
var tempX = 0;
var tempY = 0;

// Main function to retrieve mouse x-y pos.s

function getMouseXY(e) {
  if (IE) { // grab the x-y pos.s if browser is IE
    tempX = event.clientX + document.body.scrollLeft;
    tempY = event.clientY + document.body.scrollTop;
  } else {  // grab the x-y pos.s if browser is NS
    tempX = e.pageX;
    tempY = e.pageY;
  }  
  // catch possible negative values in NS4
  if (tempX < 0){tempX = 0}
  if (tempY < 0){tempY = 0}  

  // show the position values in the form named Show
  // in the text fields named MouseX and MouseY
  console.log(tempX, tempY);
  return true;
}

检测鼠标在 Iframe 上的移动

window.frames['showTime'].document.onmousemove = getMouseXY;

检测父级iframe下子级iframe中的鼠标移动
window.frames['showTime'].document.getElementById("myFrame").contentWindow.onmousemove = getMouseXY;

在浏览器中,当鼠标没有移动时触发IDLE检测功能。

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