web-dev-qa-db-fra.com

Détecter le déplacement de la souris sur une iframe?

J'ai un iframe qui occupe toute la fenêtre (100% de large, 100% de haut) et j'ai besoin de la fenêtre principale pour pouvoir détecter le moment où la souris a été déplacée.

Déjà essayé un attribut onMouseMove sur l'iframe et cela n'a évidemment pas fonctionné. Aussi essayé d'envelopper l'iframe dans une div comme suit:

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

.. et ça n'a pas marché. Aucune suggestion?

20
Charles Zink

Si votre cible n'est pas Opera 9 ou version antérieure et IE 9 ou version inférieure, vous pouvez utiliser l'attribut css pointer-events: none.

J'ai trouvé que c'était le meilleur moyen d'ignorer iframe. J'ajoute une classe avec cet attribut à iframe dans l'événement onMouseDown et le supprime dans l'événement onMouseUp.

Fonctionne parfaitement pour moi.

22
Jagi

Les iframes capturent les événements de souris, mais vous pouvez les transférer vers la portée parente si la stratégie inter-domaines est satisfaite. Voici comment:

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

Vous pouvez maintenant écouter mousemove sur l’élément iframe ou sur l’un de ses éléments parents; l’événement se déroulera comme prévu.

Ceci est compatible avec les navigateurs modernes. Si vous en avez besoin pour fonctionner avec IE8 et versions antérieures, vous devez utiliser les remplacements spécifiques à IE de createEvent, initMouseEvent et dispatchEvent.

21
Ozan

La page à l'intérieur de votre iframe est un document complet. Il consommera tous les événements et n'aura aucune connexion immédiate avec son document parent.

Vous devrez capturer les événements de souris à partir de javascript dans le document enfant, puis les transmettre au parent.

7
IanNorton

MouseEvent.initMouseEvent() est maintenant obsolète, donc la réponse de @ Ozan est un peu datée. Au lieu de ce qui est prévu dans sa réponse, je le fais maintenant comme ceci:

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

    });

};

Si je règle clientX & clientY, vous souhaiterez transmettre toute information de l'événement de la fenêtre de contenu à l'événement que nous allons distribuer (c'est-à-dire, si vous devez transmettre quelque chose comme screenX/screenY, faites-le ici).

5
jeremy

Dans votre cadre "parent", sélectionnez votre iframe "enfant" et détectez l'événement qui vous intéresse, dans votre cas mousemove 

Ceci est un exemple de code à utiliser dans votre cadre "parent"

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

Une autre façon de résoudre ce problème qui fonctionne bien pour moi est de désactiver les événements de déplacement de la souris sur iframe(s) avec quelque chose de similaire à mouse down:

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

puis réactivez les événements de déplacement de la souris sur la iframe(s) sur le mouse up:

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

J'ai essayé certaines des autres approches ci-dessus et elles fonctionnent, mais cela semble être l'approche la plus simple.

Crédit à: https://www.gyrocode.com/articles/how-to-detect-mousemove-event-over-iframe-element/

4
Bob

J'ai été confronté à un problème similaire, dans lequel j'avais des divs que je voulais traîner sur un iFrame. Le problème était que si le pointeur de la souris se déplaçait en dehors de la div, sur l'iFrame, les événements mousemove étaient perdus et la div cessait de glisser. Si c'est le genre de chose que vous voulez faire (au lieu de simplement détecter l'utilisateur en agitant la souris sur l'iFrame), j'ai trouvé une suggestion dans un autre sujet de question qui semble bien fonctionner lorsque je l'ai essayée.

Dans la page qui contient les éléments que vous souhaitez faire glisser, incluez également ceci:

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

Définissez son style initial comme suit:

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

Le z-index de '98' vient du fait que j'ai défini les div que je veux faire glisser sur z-index: 99, et l'iFrame sur z-index: 0.

Lorsque vous détectez la souris dans l'objet à déplacer (et non dans la fonction dragSurface div), appelez la fonction suivante dans le cadre de votre gestionnaire d'événements:

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";
}

_ {Remarque: j'ai trouvé la plupart de cela dans le code d'un autre utilisateur trouvé sur Internet!} _ La majorité de la logique est juste là pour définir la taille de la dragSurface afin qu'elle remplisse le cadre.

Ainsi, par exemple, mon gestionnaire onmousedown ressemble à ceci:

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

Lorsque le glisser s'arrête, votre gestionnaire onmouseup doit inclure un appel à ce code:

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

Enfin, vous créez l’image d’arrière-plan (AlmostTransparent.png dans mon exemple ci-dessus) et vous la rendez tout sauf complètement transparent. J'ai fait une image 8x8 avec alpha = 2.

Je n'ai testé cela que jusqu'à présent dans Chrome . Je dois aussi le faire fonctionner dans IE, et j'essaierai de mettre à jour cette réponse avec ce que je découvre là-bas!

4
Loophole
<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>
3
Anssi

J'ai trouvé une solution relativement simple à ce problème pour un problème similaire: je voulais redimensionner l'iframe et un long avec un div assis à côté. Une fois que la souris est passée sur l'iframe, jquery ne détectait plus la souris. 

Pour résoudre ce problème, j'avais un div assis avec l'iframe remplissant la même zone avec les mêmes styles, à l'exception de l'index z du div (défini sur 0) et de l'iframe (défini sur 1). Cela permettait à l'iframe d'être utilisé normalement lorsqu'il n'était pas redimensionné.

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

Lors du redimensionnement, l'index z div est défini à 2, puis à 0 par la suite. Cela signifiait que l'iframe était toujours visible mais que la superposition le bloquait, permettant ainsi à la souris d'être détectée.

2
Alistair

Ce code semble fonctionner, bien que pas très bien: 

<div id="test" onmousemove="alert('test');">
    <iframe style="width:200px; height:200px; border:1px solid black;">
        <p>test</p>
    </iframe>
</div>  

L'événement ne se déclenche pas à chaque mouvement de souris, mais seulement sur certains d'entre eux. Je ne sais pas s'il y a une sorte de tampon d'événements interne à l'intérieur de cet événement.

0
Thor Jacobsen

vous pouvez ajouter une superposition au-dessus d'iframe au début du glisser-déposer (événement onmousedown) et la supprimer lors du glisser-déposer (sur l'événement mouserup). le jquery UI.layout plugin utilise cette méthode pour résoudre ce problème.

0
sodarfish