使用JavaScript检测对iframe的点击


128

我了解,iframe如果是跨域用户,则无法判断用户在做什么。我想做的是跟踪用户是否完全单击iframe。我想象一个场景,div在之上有一个不可见的区域iframe,而the div会随后将click事件传递给iframe

这样的事情可能吗?如果是的话,我将如何处理?的iframes是广告,所以我必须在所使用的标签没有控制权。


4
可能并且有跨浏览器解决方案:stackoverflow.com/a/32138108/1064513
德米特里·科钦

Answers:


39

这样的事情可能吗?

否。您所能做的就是检测鼠标进入iframe的可能性,以及检测到鼠标返回iframe的可能性(尽管不可靠)(即,试图弄清指针在其他地方经过广告时的停留与徘徊之间的区别)在广告上)。

我想象一个场景,在iframe顶部有一个不可见的div,然后div会将click事件传递给iframe。

不,没有办法伪造点击事件。

通过按下鼠标,可以防止原始点击进入iframe。如果您可以确定何时按下鼠标按钮,则可以尝试将不可见的div移开,以便单击得以通过...但是也没有在鼠标按下之前触发的事件。

您可以尝试进行猜测,例如,通过查看指针是否已停止,猜测可能即将发生单击。但这是完全不可靠的,如果失败,您将失去点击的机会。


4
是的。还有跨浏览器解决方案:stackoverflow.com/a/32138108/1064513
Dmitry

1
我检查了这些链接,我认为答案是正确的。您只能在iframe中检测到点击,但不能检测到点击。
user568021 '16

我之所以投票,是因为这并非完全正确。您所说的大部分内容都是正确的,但是有一些变通办法,也是该线程上更流行的答案。
newms87

154

这当然是可能的。该功能适用​​于Chrome,Firefox和IE 11(可能还有其他)。

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

JSFiddle


警告:这只会检测到第一次点击。据我了解,这就是您想要的。


1
@the_joric,这是因为问题已经过去了四年,人们通常不会滚动到前几个答案。
保罗·德雷珀

3
还要注意的是,如果更改浏览器选项卡,将触发focus();。
林奈

7
它在Firefox中不起作用。JSFiddle包含隐藏此错误的错误:=而不是===。有跨浏览器解决方案(即使在IE8中也是如此):stackoverflow.com/a/32138108/1064513
德米特里·科钦

8
如果用户未先单击主文档,则模糊事件不会触发!另外,这也无法用于检测对多个iframe的点击,因为当焦点从一个iframe变为另一个iframe时,不会触发任何事件(iframe的blur事件不会触发)。
托马什卡夫卡

1
为什么对focus()有依赖性;
Prasad Shinde

107

基于Mohammed Radwan的回答,我提出了以下jQuery解决方案。基本上,它所做的是跟踪iFrame人员正在徘徊的内容。然后,如果窗口模糊,则很可能意味着用户单击了iframe标语。

应该将iframe放入带有ID的div中,以确保您知道用户点击了哪个iframe:

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

所以:

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

...这会在未悬停iFrame时将overiFrame保持为-1,或者在悬停iframe时将wrapi div中的“ bannerid”设置为。您要做的就是检查窗口模糊时是否设置了“ overiFrame”,如下所示:...

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

非常优雅的解决方案,但有一点缺点:如果用户将鼠标悬停在iFrame上时按ALT-F4,则会将其记录为点击。但这仅在FireFox中发生,但是IE,Chrome和Safari没有注册。

再次感谢Mohammed,非常有用的解决方案!


尽管我对这个答案+1了,但是它存在以下问题:1.当有多个iframe时,您单击其中一个,然后立即单击另一个iframe-未检测到第二次单击。2. iframe中的多次点击也不计在内。3.在移动设备上无法正常工作,因为您无法用手指进行“悬停”事件。
Sych

我使用以上脚本来检测远离我的站点的点击。现在,大多数广告网络都在框架中投放横幅广告。如果您单击一个,然后快速单击另一个,然后再单击一次,那么从技术上讲,我想知道您实际留下的最后一次单击。因此,就我而言,这是通缉的行为。它也可以很好地检测移动横幅广告上的点击。因此,悬停必须在执行点击之前立即启动
patrick

在SVG元素的情况下不工作在iframe中的内容:( stackoverflow.com/questions/32589735/...
谢尔盖·

@Serhiy,这是因为在单击iframe时实际上并没有退出原始页面……
patrick

6
这个答案是他们中最好的,但是,如果您希望将每次点击都接收到iframe中,则在用户点击之后就需要将注意力集中在iframe上,以监视进一步的点击。这应该添加到$(window).blur()部分:中setTimeout(function(){ window.focus(); }, 0);。现在,用户单击,将焦点放到iframe中,脚本将焦点拉回,现在可以监视将来的点击进一步关注焦点的变化。
HelpingHand 2013年

89

这是一个小型解决方案,适用于所有浏览器,甚至IE8:

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

您可以在这里进行测试:http : //jsfiddle.net/oqjgzsm0/


1
如果您有多个iframe,但不知道其ID怎么办?
shankshera 2015年

1
唯一可在最新FF中使用的跨浏览器可靠解决方案!多谢。它值得更多投票
BrainOverflow

6
@shankshera只需获取elem.id,这就是您的iframe ID :)。见jsfiddle.net/oqjgzsm0/219
托马什卡夫卡

1
我正在使用它来跟踪对社交类按钮的点击。但是由于我使用的3/4中的广告使用了iframe,因此我需要跟踪多个iframe中的点击次数。我已经更新了小提琴以允许这样做:jsfiddle.net/oqjgzsm0/273。它设置了一个新间隔,用于检查点击是否在上次点击的iframe之外。然后重置原始间隔以再次检查点击。如果没有外部点击,它不会跟踪同一iframe中的多次点击。
brouxhaha '16

14
除了以这样的速率使用连续循环间隔不是一个好主意之外,如果用户通过Tab键导航将注意力集中在iframe上,这将检测到误报
Kaiido 2016年

36

以下代码将向您显示用户是否单击/悬停或移出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>

您需要使用自己的链接替换iframe中的src。希望对您有所帮助。问候,莫。


1
根据快速测试,给定的示例(在修复URL之后)似乎在IE 8中可以正常工作,在Chrome 14.0.835.186 m中则可以可靠地工作,但在Firefox 6.0.2中则完全不能工作。
马修·弗拉申

适用于Chrome,但不适用于Firefox v62,因为单击iframe时 模糊事件时不会引发
slesh

11

刚刚找到此解决方案...我尝试过,我喜欢它..

适用于台式机和移动设备的跨域iframe!

不知道它是否万无一失

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

快乐编码


2
相同的答案(也许是更好的版本)于一年前发布在同一页面上:stackoverflow.com/a/23231136/470749
Ryan

5

您可以通过在window元素上使用blur事件来实现此目的。

这是一个jQuery插件,用于跟踪iframe的点击(单击iframe时,它将触发自定义回调函数): https //github.com/finalclap/iframeTracker-jquery

像这样使用它:

jQuery(document).ready(function($){
    $('.iframe_wrap iframe').iframeTracker({
        blurCallback: function(){
            // Do something when iframe is clicked (like firing an XHR request)
        }
    });
});

5

请参阅http://jsfiddle.net/Lcy797h2/,了解我在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();

它真棒的编码人员....我到底想要什么... @ Omar Jackman +1 ..如此有帮助捕获youtube广告的点击
saun4frsh 13-10-29

4

这适用于所有浏览器(包括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>


3

Mohammed Radwan,您的解决方案很优雅。要检测Firefox和IE中iframe的点击,您可以使用带有document.activeElement和计时器的简单方法,但是...我在整个互联网上搜索了一种方法来检测Chrome和Safari中iframe的点击。快要放弃了,我找到了你的答案。谢谢你,先生!

一些提示:我发现当直接调用init()函数而不是通过attachOnloadEvent()时,您的解决方案更加可靠。当然,您必须仅在iframe html之后调用init()。因此,它看起来像:

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

3

您可以执行以下操作将事件冒泡到父文档:

$('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);
    });
});

只需扩展事件列表以获取更多事件。


我使用了“ touchend”事件,它起作用了!您的回答对我很有帮助!

3

我遇到一种情况,我必须跟踪通过iframe拉入的社交媒体按钮的点击情况。单击该按钮将打开一个新窗口。这是我的解决方案:

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

3

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

只需在iframe上创建一个不可见的层,即可在单击时返回并在触发mouseleave事件时向上移动!
需要jQuery

此解决方案不会在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>


1

如果iframe与您的父网站位于同一域中,那么这绝对可行。我尚未针对跨域站点进行过测试。

$(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 */ });

没有jQuery,您可以尝试类似的方法,但是我没有尝试过。

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

您甚至可以过滤结果:

$(window.frames['YouriFrameId']).mousedown(function(event){   
  var eventId = $(event.target).attr('id');      
  if (eventId == 'the-id-you-want') {
   //  do something
  }
});

1

将以上答案与无需在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 );
    });

1

我们可以捕获所有点击。这样做的目的是在每次单击后将焦点重新放在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



0

在那里找到:使用JavaScript检测对iframe的点击

=>我们可以使用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');
    }
})

0

根据Paul Draper的回答,我创建了一个解决方案,当您具有在浏览器中打开其他标签的iframe时,该解决方案可以连续工作。当您返回页面时,该页面继续处于活动状态以检测对框架的单击,这是一种非常常见的情况:

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

该代码很简单,模糊事件会在单击iframe时检测到焦点丢失,并测试活动元素是否为iframe(如果您有多个iframe,您可以知道谁被选中),当您具有宣传框时,这种情况经常发生。

当您返回到页面时,第二个事件触发焦点方法。用于可见性更改事件。


0

这是使用带有hover + blur和活动元素技巧的建议方法的解决方案,不是任何库,仅是纯js。适用于FF / Chrome。除我使用@ zone117x提出的不同方法来跟踪FF的iframe点击外,其他方法大多与@Mohammed Radwan提出的方法相同,因为在没有附加用户设置的情况下window.focus无法正常工作:

发出将窗口移到最前面的请求。由于用户设置,它可能会失败,并且在此方法返回之前,不能保证窗口位于最前面。

这是复合方法:

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;
            });
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.