Wykryj kliknięcie w ramkę iframe za pomocą JavaScript

132

Rozumiem, że nie można stwierdzić, co użytkownik robi wewnątrz iframedomeny, jeśli jest to międzydomenowe. Chciałbym śledzić, czy użytkownik w ogóle kliknął w iframe. I wyobrazić sobie scenariusz, w którym nie jest niewidoczny divna szczycie iframei The divbędą tylko wtedy przejść do zdarzenia click iframe.

Czy coś takiego jest możliwe? Jeśli tak, to jak bym się do tego zabrał? iframesSą reklamy, więc nie mam żadnej kontroli nad tagów, które są używane.

Russ Bradberry
źródło
4
Jest to możliwe i jest rozwiązanie dla crossbrowser: stackoverflow.com/a/32138108/1064513
Dmitry Kochin

Odpowiedzi:

39

Czy coś takiego jest możliwe?

Nie. Wszystko, co możesz zrobić, to wykryć mysz wchodzącą w ramkę iframe i potencjalnie (choć nie niezawodnie), kiedy wraca (np. Próbując ustalić różnicę między wskaźnikiem przechodzącym nad reklamą w drodze w innym miejscu a utrzymującym się w reklamie).

Wyobrażam sobie scenariusz, w którym na górze elementu iframe znajduje się niewidoczny element div, który po prostu przekazuje zdarzenie click do elementu iframe.

Nie, nie ma sposobu, aby sfałszować kliknięcie.

Wyłapując przycisk myszy, zapobiegasz przedostawaniu się oryginalnego kliknięcia do elementu iframe. Gdybyś mógł określić, kiedy przycisk myszy ma zostać naciśnięty, możesz spróbować usunąć niewidoczny element div z drogi, aby kliknięcie przeszło ... ale nie ma też zdarzenia, które uruchamia się tuż przed ruchem myszy.

Możesz spróbować zgadnąć, na przykład patrząc, czy wskaźnik zatrzymał się, domyślając się, że wkrótce nastąpi kliknięcie. Ale jest to całkowicie niewiarygodne, a jeśli ci się nie uda, po prostu stracisz kliknięcie.

bobince
źródło
4
Tak to jest. Jest też rozwiązanie crossbrowser: stackoverflow.com/a/32138108/1064513
Dmitry Kochin,
1
Sprawdziłem te linki i myślę, że odpowiedź jest prawidłowa. Możesz wykryć tylko kliknięcie wewnątrz elementu iframe, ale nie to, co zostało kliknięte.
user568021
Głosuję przeciw, tylko dlatego, że nie jest to do końca prawdą. Większość z tego, co mówisz, jest prawdą, ale istnieją obejścia, podobnie jak bardziej popularna odpowiedź w tym wątku.
newms87
158

Jest to z pewnością możliwe. Działa to w Chrome, Firefox i IE 11 (i prawdopodobnie innych).

focus();
var listener = window.addEventListener('blur', function() {
    if (document.activeElement === document.getElementById('iframe')) {
        // clicked
    }
    window.removeEventListener('blur', listener);
});

JSFiddle


Uwaga: wykrywa tylko pierwsze kliknięcie. Jak rozumiem, to wszystko, czego chcesz.

Paul Draper
źródło
1
@the_joric, to dlatego, że minęło 4 lata od pytania, a ludzie zwykle nie przewijają pierwszych odpowiedzi.
Paul Draper,
3
Warto również zauważyć, że jeśli zmienisz karty przeglądarki, uruchomi się fokus ();
Linnay
7
NIE DZIAŁA w przeglądarce Firefox. JSFiddle zawiera błąd, który ukrywa to: = zamiast ===. Jest crossbrowser rozwiązanie (nawet w IE8): stackoverflow.com/a/32138108/1064513
Dmitry Kochin
8
Zdarzenie rozmycia nie zostanie uruchomione, jeśli użytkownik nie kliknie najpierw głównego dokumentu! Nie jest to również przydatne do wykrywania kliknięć wielu ramek iframe, ponieważ nie ma zdarzenia uruchamianego, gdy fokus zmienia się z jednej ramki na drugą ( blurzdarzenie iframe nie jest uruchamiane).
Tomáš Kafka
1
dlaczego istnieje zależność od focus ();
Prasad Shinde
109

Na podstawie odpowiedzi Mohammeda Radwana wymyśliłem następujące rozwiązanie jQuery. Zasadniczo śledzi to, co ludzie iFrame unoszą. Jeśli okno się rozmywa, najprawdopodobniej oznacza to, że użytkownik kliknął baner iframe.

element iframe należy umieścić w elemencie div z identyfikatorem, aby upewnić się, że wiesz, który element iframe kliknął użytkownik:

<div class='banner' bannerid='yyy'>
    <iframe src='http://somedomain.com/whatever.html'></iframe>
<div>

więc:

$(document).ready( function() {
    var overiFrame = -1;
    $('iframe').hover( function() {
        overiFrame = $(this).closest('.banner').attr('bannerid');
    }, function() {
        overiFrame = -1
    });

... to utrzymuje overiFrame na poziomie -1, gdy żadne elementy iFrame nie są najechane, lub „bannerid” ustawiony w opakowującym elemencie div, gdy element iframe jest najechany. Wszystko, co musisz zrobić, to sprawdzić, czy 'overiFrame' jest ustawione, gdy okno się rozmywa, na przykład: ...

    $(window).blur( function() {
        if( overiFrame != -1 )
            $.post('log.php', {id:overiFrame}); /* example, do your stats here */
    });
});

Bardzo eleganckie rozwiązanie z niewielką wadą: jeśli użytkownik naciśnie klawisz ALT-F4 podczas najeżdżania myszą na ramkę iFrame, zarejestruje to jako kliknięcie. Stało się to jednak tylko w FireFox, IE, Chrome i Safari go nie zarejestrowały.

Jeszcze raz dziękuję Mohammed, bardzo przydatne rozwiązanie!

patrick
źródło
Dałem +1 tej odpowiedzi, chociaż ma ona następujące problemy: 1. Jeśli istnieje wiele ramek iframe, klikasz jedną z nich, a następnie natychmiast drugą - drugie kliknięcie nie jest wykrywane. 2. Wielokrotne kliknięcia wewnątrz elementu iframe również nie są liczone. 3. Nie działa poprawnie na telefonie komórkowym, ponieważ nie można wykonać zdarzenia „najechanie” palcem.
Sych
Powyższy skrypt jest używany przeze mnie do wykrywania kliknięć poza moją witryną. Większość sieci reklamowych wyświetla teraz banery w ramkach. Jeśli klikniesz jedno, a potem szybko drugie, zanim opuściłeś pierwsze kliknięcie, technicznie rzecz biorąc, chcę poznać ostatnie kliknięcie, które faktycznie zostawiłeś. Więc w moim przypadku jest to pożądane zachowanie. Dobrze też wykrywa kliknięcia banerów mobilnych. Więc najechanie musi zostać uruchomione tuż przed wykonaniem kliknięcia
patrick
Nie działa w przypadku elementów svg w zawartości iframe :( stackoverflow.com/questions/32589735/…
Serhiy
@Serhiy, to dlatego, że tak naprawdę nie opuszczasz oryginalnej strony po kliknięciu ramki iframe ...
patrick
7
Ta odpowiedź jest najlepsza z nich, jednak jeśli chcesz otrzymywać każde kliknięcie elementu iframe, musisz skupić się na nim po kliknięciu przez użytkownika , aby monitorować dalsze kliknięcia. To powinno być dodawane do sekcji $ (okno) .blur () setTimeout(function(){ window.focus(); }, 0);. Teraz użytkownik klika, umieszcza fokus w elemencie iframe, skrypt cofa fokus z powrotem i może teraz monitorować dalsze zmiany fokusu od przyszłych kliknięć.
HelpingHand
92

To małe rozwiązanie, które działa we wszystkich przeglądarkach nawet IE8:

var monitor = setInterval(function(){
    var elem = document.activeElement;
    if(elem && elem.tagName == 'IFRAME'){
        clearInterval(monitor);
        alert('clicked!');
    }
}, 100);

Możesz to przetestować tutaj: http://jsfiddle.net/oqjgzsm0/

Dmitrij Kochin
źródło
1
A co, jeśli masz kilka ramek iframe i nie znasz ich identyfikatora?
shankshera
1
jedyne niezawodne rozwiązanie dla różnych przeglądarek, które działa również w najnowszym FF! Wielkie dzięki. Zasługuje na więcej głosów
BrainOverflow
6
@shankshera Po prostu pobierz elem.id, to twój identyfikator iframe :). Zobacz jsfiddle.net/oqjgzsm0/219
Tomáš Kafka
1
Używam tego do śledzenia kliknięć w przyciski społecznościowe. Ale ponieważ 3/4 z nich używa ramek iframe, muszę śledzić kliknięcia w wielu ramkach iframe. Zaktualizowałem skrzypce, aby to umożliwić: jsfiddle.net/oqjgzsm0/273 . Ustawia nowy interwał, który sprawdza, czy kliknięcie jest poza ostatnią klikniętą ramką iframe. Następnie resetuje pierwotny interwał, aby ponownie sprawdzić kliknięcia. Nie śledzi wielu kliknięć w tym samym elemencie iframe bez kliknięcia poza nim.
brouxhaha
14
Pomijając fakt, że używanie ciągłego zapętlenia interwału przy takiej częstotliwości nie jest dobrym pomysłem, wykryje to fałszywe alarmy, jeśli użytkownik ustawi fokus na
ramce
36

Poniższy kod pokaże Ci, czy użytkownik kliknie / najedzie kursorem lub wyjdzie z ramki iframe: -

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Detect IFrame Clicks</title>
<script type="text/javascript">
    $(document).ready(function() {
        var isOverIFrame = false;

        function processMouseOut() {
            log("IFrame mouse >> OUT << detected.");
            isOverIFrame = false;
            top.focus();
        }

        function processMouseOver() {
            log("IFrame mouse >> OVER << detected.");
            isOverIFrame = true;
        }

        function processIFrameClick() {
            if(isOverIFrame) {
                // replace with your function
                log("IFrame >> CLICK << detected. ");
            }
        }

        function log(message) {
            var console = document.getElementById("console");
            var text = console.value;
            text = text + message + "\n";
            console.value = text;
        }

        function attachOnloadEvent(func, obj) {
            if(typeof window.addEventListener != 'undefined') {
                window.addEventListener('load', func, false);
            } else if (typeof document.addEventListener != 'undefined') {
                document.addEventListener('load', func, false);
            } else if (typeof window.attachEvent != 'undefined') {
                window.attachEvent('onload', func);
            } else {
                if (typeof window.onload == 'function') {
                    var oldonload = onload;
                    window.onload = function() {
                        oldonload();
                        func();
                    };
                } else {
                    window.onload = func;
                }
            }
        }

        function init() {
            var element = document.getElementsByTagName("iframe");
            for (var i=0; i<element.length; i++) {
                element[i].onmouseover = processMouseOver;
                element[i].onmouseout = processMouseOut;
            }
            if (typeof window.attachEvent != 'undefined') {
                top.attachEvent('onblur', processIFrameClick);
            }
            else if (typeof window.addEventListener != 'undefined') {
                top.addEventListener('blur', processIFrameClick, false);
            }
        }

        attachOnloadEvent(init);
    });
</script>
</head>
<body>
<iframe src="www.google.com" width="100%" height="1300px"></iframe>
<br></br>
<br></br>
<form name="form" id="form" action=""><textarea name="console"
id="console" style="width: 100%; height: 300px;" cols="" rows=""></textarea>
<button name="clear" id="clear" type="reset">Clear</button>
</form>
</body>
</html>

Musisz zastąpić src w ramce iframe własnym linkiem. Mam nadzieję, że to pomoże. Pozdrawiam, Mo.

Mohammed Radwan
źródło
1
Na podstawie szybkich testów podany przykład (po poprawieniu adresu URL) wydaje się działać w IE 8, trochę niezawodnie w Chrome 14.0.835.186 m, ale wcale nie w Firefox 6.0.2.
Matthew Flaschen,
Działa dobrze w przeglądarce Chrome, ale nie działa w przeglądarce Firefox v62, ponieważ po kliknięciu zdarzenia rozmycia
ramki
11

Właśnie znalazłem to rozwiązanie ... Wypróbowałem, pokochałem ...

Działa dla międzydomenowych ramek iframe na komputery i urządzenia mobilne!

Nie wiem, czy jest jeszcze niezawodny

window.addEventListener('blur',function(){
      if(document.activeElement.id == 'CrossDomainiframeId'){
        //do something :-)
      }
});

Miłego kodowania

Tony
źródło
2
Ta sama odpowiedź (może nieco lepsza wersja) została opublikowana rok wcześniej tutaj, na tej samej stronie: stackoverflow.com/a/23231136/470749
Ryan
5

Możesz to osiągnąć za pomocą zdarzenia blur na elemencie okna.

Oto wtyczka jQuery do śledzenia kliknięć w elementach iframe (uruchomi niestandardową funkcję zwrotną po kliknięciu elementu iframe): https://github.com/finalclap/iframeTracker-jquery

Użyj tego w ten sposób:

jQuery(document).ready(function($){
    $('.iframe_wrap iframe').iframeTracker({
        blurCallback: function(){
            // Do something when iframe is clicked (like firing an XHR request)
        }
    });
});
Vince
źródło
5

zobacz http://jsfiddle.net/Lcy797h2/ dla mojego rozwlekłego rozwiązania, które nie działa niezawodnie w IE

        $(window).on('blur',function(e) {    
            if($(this).data('mouseIn') != 'yes')return;
            $('iframe').filter(function(){
                return $(this).data('mouseIn') == 'yes';
            }).trigger('iframeclick');    
        });

        $(window).mouseenter(function(){
            $(this).data('mouseIn', 'yes');
        }).mouseleave(function(){
            $(this).data('mouseIn', 'no');
        });

        $('iframe').mouseenter(function(){
            $(this).data('mouseIn', 'yes');
            $(window).data('mouseIn', 'yes');
        }).mouseleave(function(){
            $(this).data('mouseIn', null);
        });

        $('iframe').on('iframeclick', function(){
            console.log('Clicked inside iframe');
            $('#result').text('Clicked inside iframe'); 
        });
        $(window).on('click', function(){
            console.log('Clicked inside window');
            $('#result').text('Clicked inside window'); 
        }).blur(function(){
            console.log('window blur');
        });

        $('<input type="text" style="position:absolute;opacity:0;height:0px;width:0px;"/>').appendTo(document.body).blur(function(){
                $(window).trigger('blur');
            }).focus();
DiverseAndRemote.com
źródło
Jego niesamowity koder… czego właściwie chcę… +1 dla @Omar Jackman… bardzo pomocny w przechwytywaniu kliknięć w reklamę na youtube
saun4frsh
4

Działa to dla mnie we wszystkich przeglądarkach (w tym Firefox)

https://gist.github.com/jaydson/1780598

https://jsfiddle.net/sidanmor/v6m9exsw/

var myConfObj = {
  iframeMouseOver : false
}
window.addEventListener('blur',function(){
  if(myConfObj.iframeMouseOver){
    console.log('Wow! Iframe Click!');
  }
});

document.getElementById('idanmorblog').addEventListener('mouseover',function(){
   myConfObj.iframeMouseOver = true;
});
document.getElementById('idanmorblog').addEventListener('mouseout',function(){
    myConfObj.iframeMouseOver = false;
});
<iframe id="idanmorblog" src="https://sidanmor.com/" style="width:400px;height:600px" ></iframe>

<iframe id="idanmorblog" src="https://sidanmor.com/" style="width:400px;height:600px" ></iframe>

sidanmor
źródło
3

Mohammed Radwan, Twoje rozwiązanie jest eleganckie. Aby wykryć kliknięcia iframe w Firefoksie i IE, możesz użyć prostej metody z document.activeElement i licznikiem czasu, jednak ... Przeszukałem wszystkie interweb w poszukiwaniu metody wykrywania kliknięć w ramce iframe w Chrome i Safari. Na skraju rezygnacji znajduję twoją odpowiedź. Dziękuję Panu!

Kilka wskazówek: Odkryłem, że Twoje rozwiązanie jest bardziej niezawodne podczas bezpośredniego wywoływania funkcji init (), a nie przez attachOnloadEvent (). Oczywiście, aby to zrobić, musisz wywołać init () tylko po elemencie iframe html. Więc wyglądałoby to mniej więcej tak:

<script>
var isOverIFrame = false;
function processMouseOut() {
    isOverIFrame = false;
    top.focus();
}
function processMouseOver() { isOverIFrame = true; }
function processIFrameClick() {
    if(isOverIFrame) {
    //was clicked
    }
}

function init() {
    var element = document.getElementsByTagName("iframe");
    for (var i=0; i<element.length; i++) {
        element[i].onmouseover = processMouseOver;
        element[i].onmouseout = processMouseOut;
    }
    if (typeof window.attachEvent != 'undefined') {
        top.attachEvent('onblur', processIFrameClick);
    }
    else if (typeof window.addEventListener != 'undefined') {
        top.addEventListener('blur', processIFrameClick, false);
    }
}
</script>

<iframe src="http://google.com"></iframe>

<script>init();</script>
zone117x
źródło
3

Możesz to zrobić, aby przenieść wydarzenia do dokumentu nadrzędnego:

$('iframe').load(function() {
    var eventlist = 'click dblclick \
                    blur focus focusin focusout \
                    keydown keypress keyup \
                    mousedown mouseenter mouseleave mousemove mouseover mouseout mouseup mousemove \
                    touchstart touchend touchcancel touchleave touchmove';

    var iframe = $('iframe').contents().find('html');

    // Bubble events to parent
    iframe.on(eventlist, function(event) {
        $('html').trigger(event);
    });
});

Po prostu rozszerz listę wydarzeń o więcej wydarzeń.

Taner Topal
źródło
Użyłem zdarzenia „touchend” i zadziałało! Twoja odpowiedź bardzo mi pomogła!
3

Znalazłem się w sytuacji, w której musiałem śledzić kliknięcia przycisku mediów społecznościowych przeciągniętego przez element iframe. Po kliknięciu przycisku zostanie otwarte nowe okno. Oto moje rozwiązanie:

var iframeClick = function () {
    var isOverIframe = false,
    windowLostBlur = function () {
        if (isOverIframe === true) {
            // DO STUFF
            isOverIframe = false;
        }
    };
    jQuery(window).focus();
    jQuery('#iframe').mouseenter(function(){
        isOverIframe = true;
        console.log(isOverIframe);
    });
    jQuery('#iframe').mouseleave(function(){
        isOverIframe = false;
        console.log(isOverIframe);
    });
    jQuery(window).blur(function () {
        windowLostBlur();
    });
};
iframeClick();
pizzarob
źródło
3

http://jsfiddle.net/QcAee/406/

Po prostu utwórz niewidoczną warstwę na ramce iframe, która cofa się po kliknięciu i podnosi się, gdy zdarzenie mouseleave zostanie uruchomione !!
Potrzebujesz jQuery

to rozwiązanie nie propaguje pierwszego kliknięcia wewnątrz elementu iframe!

$("#invisible_layer").on("click",function(){
		alert("click");
		$("#invisible_layer").css("z-index",-11);

});
$("iframe").on("mouseleave",function(){
		$("#invisible_layer").css("z-index",11);
});
iframe {
    width: 500px;
    height: 300px;
}
#invisible_layer{
  position: absolute;
  background-color:trasparent;
  width: 500px;
  height:300px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="message"></div>
<div id="invisible_layer">

</div>
<iframe id="iframe" src="//example.com"></iframe>

r1si
źródło
1

To z pewnością działa, jeśli element iframe pochodzi z tej samej domeny, co Twoja witryna nadrzędna. Nie testowałem go pod kątem witryn międzydomenowych.

$(window.frames['YouriFrameId']).click(function(event){  /* do something here  */ });
$(window.frames['YouriFrameId']).mousedown(function(event){ /* do something here */ });
$(window.frames['YouriFrameId']).mouseup(function(event){ /* do something here */ });

Bez jQuery mógłbyś spróbować czegoś takiego, ale znowu tego nie próbowałem.

window.frames['YouriFrameId'].onmousedown = function() { do something here }

Możesz nawet filtrować wyniki:

$(window.frames['YouriFrameId']).mousedown(function(event){   
  var eventId = $(event.target).attr('id');      
  if (eventId == 'the-id-you-want') {
   //  do something
  }
});
Jonathan Tonge
źródło
1

Połączenie powyższej odpowiedzi z możliwością wielokrotnego klikania bez klikania poza ramką iframe.

    var eventListener = window.addEventListener('blur', function() {
    if (document.activeElement === document.getElementById('contentIFrame')) {
        toFunction(); //function you want to call on click
        setTimeout(function(){ window.focus(); }, 0);
    }
    window.removeEventListener('blur', eventListener );
    });
Talha Asif
źródło
1

Możemy złapać wszystkie kliknięcia. Chodzi o to, aby po każdym kliknięciu zresetować fokus na elemencie poza iFrame:

    <input type="text" style="position:fixed;top:-1000px;left:-1000px">
    <div id="message"></div>
    <iframe id="iframe" src="//example.com"></iframe>
    <script>
        focus();
        addEventListener('blur', function() {
            if(document.activeElement = document.getElementById('iframe')) {
                message.innerHTML += 'Clicked';
                setTimeout(function () {
                    document.querySelector("input").focus();
                    message.innerHTML += ' - Reset focus,';
                }, 1000);
            }  
        });
    </script>

JSFiddle

Alexandre Muraviov
źródło
0

Wierzę, że możesz zrobić coś takiego:

$('iframe').contents().click(function(){function to record click here });

używając jQuery, aby to osiągnąć.

Daniel Sellers
źródło
0

Jak tam znaleziono: Wykryj kliknięcie w ramkę iframe za pomocą JavaScript

=> Możemy użyć iframeTracker-jquery :

$('.carousel-inner .item').each(function(e) {
    var item = this;
    var iFrame = $(item).find('iframe');
    if (iFrame.length > 0) {
        iFrame.iframeTracker({
            blurCallback: function(){
                // Do something when iFrame is clicked (like firing an XHR request)
                onItemClick.bind(item)(); // calling regular click with right context
                console.log('IFrameClick => OK');
            }
        });
        console.log('IFrameTrackingRegistred => OK');
    }
})
Mickaël
źródło
0

Opierając się na odpowiedzi Paula Drapera, stworzyłem rozwiązanie, które działa nieprzerwanie, gdy masz ramki iframe otwierające inne karty w przeglądarce. Po powrocie strona nadal jest aktywna, aby wykryć kliknięcie w ramach, jest to bardzo częsta sytuacja:

          focus();
        $(window).blur(() => {
           let frame = document.activeElement;
           if (document.activeElement.tagName == "IFRAME") {
             // Do you action.. here  frame has the iframe clicked
              let frameid = frame.getAttribute('id')
              let frameurl = (frame.getAttribute('src'));
           }            
        });

        document.addEventListener("visibilitychange", function () {
            if (document.hidden) {

            } else {
                focus();
            }
        });

Kod jest prosty, zdarzenie rozmycia wykrywa utratę fokusu po kliknięciu elementu iframe i sprawdza, czy aktywnym elementem jest iframe (jeśli masz kilka elementów iframe, możesz wiedzieć, kto został wybrany) taka sytuacja często występuje, gdy masz ramki reklamowe .

Drugie zdarzenie wyzwala metodę fokusu po powrocie na stronę. jest używane jako zdarzenie zmiany widoczności.

freedeveloper
źródło
0

Oto rozwiązanie wykorzystujące sugerowane podejścia z hover + blur i triki z aktywnymi elementami, a nie żadne biblioteki, tylko czysty js. Działa dobrze na FF / Chrome. Przeważnie podejście jest takie samo, jak zaproponował @Mohammed Radwan, z wyjątkiem tego, że używam innej metody proponowanej przez @ zone117x do śledzenia kliknięć iframe dla FF, ponieważ window.focus nie działa bez dodatkowych ustawień użytkownika :

Prosi o przesunięcie okna do przodu. Może się nie powieść z powodu ustawień użytkownika i nie ma gwarancji, że okno będzie na pierwszym miejscu przed zwróceniem tej metody.

Oto metoda złożona:

function () {
    const state = {};

    (function (setup) {
        if (typeof window.addEventListener !== 'undefined') {
            window.addEventListener('load', setup, false);
        } else if (typeof document.addEventListener !== 'undefined') {
            document.addEventListener('load', setup, false);
        } else if (typeof window.attachEvent !== 'undefined') {
            window.attachEvent('onload', setup);
        } else {
            if (typeof window.onload === 'function') {
                const oldonload = onload;
                window.onload = function () {
                    oldonload();
                    setup();
                };
            } else {
                window.onload = setup;
            }
        }
    })(function () {
        state.isOverIFrame = false;
        state.firstBlur = false;
        state.hasFocusAcquired = false;

        findIFramesAndBindListeners();

        document.body.addEventListener('click', onClick);

        if (typeof window.attachEvent !== 'undefined') {
            top.attachEvent('onblur', function () {
                state.firstBlur = true;
                state.hasFocusAcquired = false;
                onIFrameClick()
            });
            top.attachEvent('onfocus', function () {
                state.hasFocusAcquired = true;
                console.log('attachEvent.focus');
            });
        } else if (typeof window.addEventListener !== 'undefined') {
            top.addEventListener('blur', function () {
                state.firstBlur = true;
                state.hasFocusAcquired = false;
                onIFrameClick();
            }, false);
            top.addEventListener('focus', function () {
                state.hasFocusAcquired = true;
                console.log('addEventListener.focus');
            });
        }

        setInterval(findIFramesAndBindListeners, 500);
    });

    function isFF() {
        return navigator.userAgent.search(/firefox/i) !== -1;
    }

    function isActiveElementChanged() {
        const prevActiveTag = document.activeElement.tagName.toUpperCase();
        document.activeElement.blur();
        const currActiveTag = document.activeElement.tagName.toUpperCase();
        return !prevActiveTag.includes('BODY') && currActiveTag.includes('BODY');
    }

    function onMouseOut() {
        if (!state.firstBlur && isFF() && isActiveElementChanged()) {
            console.log('firefox first click');
            onClick();
        } else {
            document.activeElement.blur();
            top.focus();
        }
        state.isOverIFrame = false;
        console.log(`onMouseOut`);
    }

    function onMouseOver() {
        state.isOverIFrame = true;
        console.log(`onMouseOver`);
    }

    function onIFrameClick() {
        console.log(`onIFrameClick`);
        if (state.isOverIFrame) {
            onClick();
        }
    }

    function onClick() {
        console.log(`onClick`);
    }

    function findIFramesAndBindListeners() {
        return Array.from(document.getElementsByTagName('iframe'))
            .forEach(function (element) {
                element.onmouseover = onMouseOver;
                element.onmouseout = onMouseOut;
            });
    }
}
slesh
źródło
0

Założenia -

  1. Twój skrypt działa poza ramką iframe, ALE NIE w najbardziej zewnętrznym oknie window.top. (W przypadku okna najbardziej zewnętrznego wystarczające są inne rozwiązania rozmycia)
  2. Nowa strona jest otwierana, zastępując bieżącą stronę / nową stronę w nowej karcie, a sterowanie jest przełączane na nową kartę.

Działa to zarówno w przypadku ramek iframe źródłowych, jak i bezkośnych

var ifr = document.getElementById("my-iframe");
var isMouseIn;
ifr.addEventListener('mouseenter', () => {
    isMouseIn = true;
});
ifr.addEventListener('mouseleave', () => {
    isMouseIn = false;
});
window.document.addEventListener("visibilitychange", () => {
    if (isMouseIn && document.hidden) {
        console.log("Click Recorded By Visibility Change");
    }
});
window.addEventListener("beforeunload", (event) => {
    if (isMouseIn) {
        console.log("Click Recorded By Before Unload");
    }
});

Jeśli nowa karta jest otwarta / ta sama strona zostaje rozładowana, a wskaźnik myszy znajduje się w ramce iframe, uważa się, że kliknięcie

Sahil Maniar
źródło