Javascript 在 iframe 上检测鼠标移动?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5645485/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 18:14:57  来源:igfitidea点击:

Detect mousemove when over an iframe?

javascriptiframedom-eventsonmousemove

提问by Charles Zink

I have an iframe that takes up the entire window (100% wide, 100% high), and I need the main window to be able to detect when the mouse has been moved.

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

Already tried an onMouseMoveattribute on the iframe and it obviously didn't work. Also tried wrapping the iframe in a div like so:

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

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

.. and it didn't work. Any suggestions?

..它没有用。有什么建议?

回答by ?ukasz Jagodziński

If your target isn't Opera 9 or lower and IE 9 or lower you can use css attribute pointer-events: none.

如果您的目标不是 Opera 9 或更低版本和 IE 9 或更低版本,您可以使用 css 属性pointer-events: none

I found it the best way just to ignore iframe. I add class with this attribute to iframe in onMouseDownevent and remove in onMouseUpevent.

我发现它是忽略 iframe 的最佳方式。我在onMouseDown事件中将具有此属性的类添加到 iframe 并在事件中删除onMouseUp

Works perfect for me.

非常适合我。

回答by Ozan

Iframes capture mouse events, but you can transfer the events to the parent scope if the cross-domain policy is satisfied. Here's how:

iframe 捕获鼠标事件,但如果满足跨域策略,您可以将事件传输到父作用域。就是这样:

// 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);

You can now listen for mousemove on the iframe element or any of its parent elements -- the event will bubble up as you would expect.

您现在可以在 iframe 元素或其任何父元素上侦听 mousemove - 该事件将如您​​所愿地冒泡。

This is compatible with modern browsers. If you need it to work with IE8 and below, you'll need to use the IE-specific replacements of createEvent, initMouseEvent, and dispatchEvent.

这与现代浏览器兼容。如果你需要它的工作与IE8及以下,你需要使用的IE特有的替代品createEventinitMouseEventdispatchEvent

回答by jeremy

MouseEvent.initMouseEvent()is now deprecated, so @Ozan's answer is a bit dated. As an alternative to what's provided in his answer, I'm now doing it like this:

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 );

    });

};

Where I'm setting clientX& clientYyou'll want to pass any info from the content window's event to the event we'll be dispatching (i.e., if you need to pass something like screenX/screenY, do it there).

在我设置的位置clientXclientY您需要将内容窗口事件中的任何信息传递给我们将要调度的事件(即,如果您需要传递诸如screenX/ 之类的内容screenY,请在那里执行)。

回答by Bob

Another way to solve this that work well for me is to disable mouse move events on the iframe(s)with something like on the mouse down:

解决这个问题的另一种方法对我来说效果很好,是在 上禁用鼠标移动事件,iframe(s)例如mouse down

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

and then, re-enable mouse move events on the iframe(s)on the mouse up:

然后,重新启用鼠标移动事件iframe(s)mouse up

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

I tried some of the other approaches above and they work, but this seems to be the simplest approach.

我尝试了上面的一些其他方法并且它们有效,但这似乎是最简单的方法。

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

归功于:https: //www.gyrocode.com/articles/how-to-detect-mousemove-event-over-iframe-element/

回答by IanNorton

The page inside your iframe is a complete document. It will consume all events and have no immediate connection to it's parent document.

iframe 中的页面是一个完整的文档。它将消耗所有事件并且没有直接连接到它的父文档。

You will need to catch the mouse events from javascript inside the child document and then pass this somehow to the parent.

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

回答by GibboK

On your "parent" frame, select your "child" iframe and detect the event you are interested, in your case mousemove

在您的“父”框架上,选择您的“子”iframe 并检测您感兴趣的事件,在您的情况下 mousemove

This an example of code to be used in your "parent" frame

这是在“父”框架中使用的代码示例

document.getElementById('yourIFrameHere').contentDocument.addEventListener('mousemove', function (event) {
                console.log(, event.pageX, event.pageY, event.target.id);
            }.bind(this));

回答by Loophole

I have been faced with a similar issue, where I had div's that I wanted to drag around over an iFrame. Problem was that if the mouse pointer moved outside the div, onto the iFrame, the mousemove events were lost and the div stopped dragging. If this is the sort of thing you want to do (as opposed to just detecting the user waving the mouse over the iFrame), I found a suggestion in another question threadwhich seems to work well when I tried it.

我遇到过类似的问题,我有一个 div,我想在 iFrame 上拖动它。问题是,如果鼠标指针移到 div 之外,移到 iFrame 上,则 mousemove 事件丢失并且 div 停止拖动。如果这是你想做的事情(而不是仅仅检测用户在 iFrame 上挥动鼠标),我在另一个问题线程中找到了一个建议,当我尝试它时,它似乎工作得很好。

In the page that contains the and the things you want to drag, also include a like this:

在包含和要拖拽的东西的页面中,还包括这样的:

<div class="dragSurface" id="dragSurface">
<!-- to capture mouse-moves over the iframe-->
</div>

Set it's initial style to be something like this:

将其初始样式设置为如下所示:

.dragSurface
{
  background-image: url('../Images/AlmostTransparent.png');
  position: absolute;
  z-index: 98;
  width: 100%;
  visibility: hidden;
}

The z-index of '98' is because I set the div's I want to drag around to be z-index:99, and the iFrame at z-index:0.

'98' 的 z-index 是因为我将要拖动的 div 设置为 z-index:99,并将 iFrame 设置为 z-index:0。

When you detect the mousedown in the to-be-dragged object (not the dragSurface div), call the following function as part of your event handler:

当您在要拖动的对象(不是 dragSurface div)中检测到 mousedown 时,调用以下函数作为事件处理程序的一部分:

function activateDragSurface ( surfaceId )
{
  var surface = document.getElementById( surfaceId );
  if ( surface == null ) return;

  if ( typeof window.innerWidth != 'undefined' )
  { viewportheight = window.innerHeight; } 
  else
  { viewportheight = document.documentElement.clientHeight; }

  if ( ( viewportheight > document.body.parentNode.scrollHeight ) && ( viewportheight > document.body.parentNode.clientHeight ) )
  { surface_height = viewportheight; }
  else
  {
    if ( document.body.parentNode.clientHeight > document.body.parentNode.scrollHeight )
    { surface_height = document.body.parentNode.clientHeight; }
    else
    { surface_height = document.body.parentNode.scrollHeight; }
  }

  var surface = document.getElementById( surfaceId );
  surface.style.height = surface_height + 'px';
  surface.style.visibility = "visible";
}

Note: I cribbed most of that from somebody else's code I found on the internet!The majority of the logic is just there to set the size of the dragSurface to fill the frame.

注意:我从网上找到的其他人的代码中抄袭了大部分内容!大多数逻辑只是设置dragSurface 的大小以填充框架。

So, for example, my onmousedown handler looks like this:

因此,例如,我的 onmousedown 处理程序如下所示:

function dragBegin(elt)
{
  if ( document.body.onmousemove == null )
  {
    dragOffX = ( event.pageX - elt.offsetLeft );
    dragOffY = ( event.pageY - elt.offsetTop );
    document.body.onmousemove = function () { dragTrack( elt ) };
    activateDragSurface( "dragSurface" ); // capture mousemoves over the iframe.
  }
}

When dragging stops, your onmouseup handler should include a call to this code:

当拖动停止时,您的 onmouseup 处理程序应包括对以下代码的调用:

function deactivateDragSurface( surfaceId )
{
  var surface = document.getElementById( surfaceId );
  if ( surface != null ) surface.style.visibility = "hidden";
}

Finally, you create the background image (AlmostTransparent.png in my example above), and make it anything except completelytransparent. I made an 8x8 image with alpha=2.

最后,您创建背景图像(在我上面的示例中为 AlmostTransparent.png),并将其设置为完全透明以外的任何内容。我制作了一个 alpha=2 的 8x8 图像。

I have only tested this in Chrome so far. I need to get it working in IE as well, and will try and update this answer with what I discover there!

到目前为止,我只在 Chrome 中对此进行了测试。我也需要让它在 IE 中工作,并将尝试用我在那里发现的内容更新这个答案!

回答by Anssi

<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>

回答by Alistair

I found a relatively simple solution to this for a similar issue I was having where I wanted to resize the iframe and a long with a div sitting next to it. Once the mouse went over the iframe jquery would stop detecting the mouse.

对于一个类似的问题,我找到了一个相对简单的解决方案,我想调整 iframe 的大小,并且旁边有一个 div。一旦鼠标越过 iframe jquery 将停止检测鼠标。

To fix this I had a div sitting with the iframe both filling the same area with the same styles except for the z-index of the div (set to 0) and the iframe (set to 1). This allowed for the iframe to be used normally when not resizing.

为了解决这个问题,我有一个 div 与 iframe 一起使用相同的样式填充同一区域,除了 div 的 z-index(设置为 0)和 iframe(设置为 1)。这允许 iframe 在不调整大小时正常使用。

<div id="frameOverlay"></div>  
<iframe></iframe>

When resizing, the div z-index gets set to 2 and then back to 0 afterwards. This meant the iframe was still visible but the overlay was blocking it, allowing for the mouse to be detected.

调整大小时,div z-index 设置为 2,然后再设置为 0。这意味着 iframe 仍然可见,但覆盖层阻止了它,从而可以检测到鼠标。

回答by sodarfish

you can add a overlay on top of iframe when drag begin ( onmousedown event ) , and remove it when drag end ( on mouserup event ). the jquery UI.layout pluginuse this method to solve this problem.

您可以在拖动开始时(onmousedown 事件)在 iframe 顶部添加一个叠加层,并在拖动结束时(在 mouserup 事件上)移除它。在jQuery的UI.layout插件使用此方法来解决这个问题。