【问题标题】:Detect mousemove when over an iframe?在 iframe 上时检测 mousemove?
【发布时间】:2011-08-04 11:13:01
【问题描述】:

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

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

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

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

【问题讨论】:

  • 我不是 100% 确定。已经好几年了。我认为您需要在子页面(加载到框架中的页面)中捕获鼠标悬停事件。

标签: javascript iframe dom-events onmousemove


【解决方案1】:

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

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

非常适合我。

【讨论】:

  • 这是一个很棒的,我认为最好的解决方案。目前唯一的缺点是 IE 还不支持指针事件属性。 caniuse.com/#search=pointer-events
  • 除了 iframe 仍然可以交互之外,有什么办法可以让它工作吗?
  • 唯一的问题是你不能以任何方式与 iframe 交互,指针事件设置为无,所以对于很多用例来说这不起作用
  • 哇。我花了几个小时在这上面。想想这很容易。非常感谢!
【解决方案2】:

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

您现在可以在 iframe 元素或其任何父元素上侦听 mousemove ——该事件将如您​​所料那样冒泡。

这与现代浏览器兼容。如果您需要它与 IE8 及以下版本一起使用,则需要使用 IE 特定的替换 createEventinitMouseEventdispatchEvent

【讨论】:

  • 查看我的最新答案,了解有关弃用和如何处理它的更多信息
【解决方案3】:

另一种对我很有效的解决方法是在iframe(s) 上禁用鼠标移动事件,例如在mouse down 上:

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

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

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

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

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

【讨论】:

  • 对我有用的非常简单的解决方案。值得一试。
【解决方案4】:

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,在那里做)。

【讨论】:

  • 一个好的开始,但不完整。并非所有相关数据都从 iframe 上捕获的事件复制到生成的克隆。缺少的一件事是 evt.buttons。看看 MouseEvent 有多少个键,我几乎可以肯定这不是唯一缺少的东西。通过将此解决方案与 Jagi 的解决方案并排运行,应该能够逐步“填补空白”。
  • 可能会使用 Object.keys 遍历所有键,并进行标准克隆,然后仅手动执行那些发生变化的键,例如解决方案中的 .clientX、.clientY。
  • 我正在使用这个解决方案并添加了一行,即 evt.buttons = event.buttons,它适用于我正在做的事情。正如我所说,对于其他用例,您可能需要复制更多内容。
  • IE没有CustomEvent,但是有一个polyfill,见developer.mozilla.org/en-US/docs/Web/API/CustomEvent/…
  • @dieterh 很高兴听到它
【解决方案5】:

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

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

【讨论】:

  • 知道如何正确传递鼠标坐标吗?
【解决方案6】:

我遇到过类似的问题,我想在 iFrame 上拖动 div。问题是,如果鼠标指针移到 div 之外,移到 iFrame 上,mousemove 事件就会丢失并且 div 停止拖动。如果这是您想要做的事情(而不是仅仅检测用户在 iFrame 上挥动鼠标),我在another question thread 中找到了一个建议,当我尝试它时似乎效果很好。

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

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

将其初始样式设置为:

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

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

当您检测到待拖动对象(而不是 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";
}

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

例如,我的 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.
  }
}

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

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

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

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

【讨论】:

  • 这对我来说非常有效。另外,我从this post 引用了一个稍微简化的 div 覆盖策略
【解决方案7】:

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

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

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

【讨论】:

  • 这段代码对吗?因为我没有从带有 iframe 的模态中获取数据。没有任何反应,没有错误。
【解决方案8】:

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

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

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

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

【讨论】:

  • 借鉴了你的想法。这是一个很好的答案,因为您不必担心将事件从孩子冒泡到父母
【解决方案9】:
<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>

【讨论】:

    【解决方案10】:

    这是我使用 jQuery 的解决方案。您可以像我在下面那样检测多个事件。将 .on() 事件处理程序放在 .on('load') 事件处理程序中是必要的,因为当 iframe 导航到新页面时,它将停止检测 iframe 内容事件。此外,我认为这仅在 iframe 内容与父页面位于同一域中时才有效,因为安全原因,并且没有办法解决这个问题。

    $(document).ready(function() {
        $('#iframe_id').on('load', function() {
            $('#iframe_id').contents().on('click mousemove scroll', handlerFunction);
        });
    });
    
    handlerFunction() {
        //do stuff here triggered by events in the iframe
    }
    

    【讨论】:

      【解决方案11】:

      文档中的基本方式

      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 检测功能。

      【讨论】:

        【解决方案12】:

        您可以在拖动开始时(onmousedown 事件)在 iframe 顶部添加叠加层,并在拖动结束时将其移除(在 mouserup 事件中)。 jquery UI.layout plugin使用这个方法来解决这个问题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-02-10
          • 1970-01-01
          • 2015-10-08
          • 2014-07-09
          • 1970-01-01
          • 1970-01-01
          • 2015-04-28
          • 2021-02-01
          相关资源
          最近更新 更多