151

iframe我知道如果它是跨域的,则无法判断用户在内部做什么。我想做的是跟踪用户是否在iframe. 我想象一个场景,div在顶部有一个不可见的,iframe然后div会将点击事件传递给iframe.

这样的事情可能吗?如果是,那我该怎么办?是iframes广告,所以我无法控制使用的标签。

4

23 回答 23

181

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

const message = document.getElementById("message");

// main document must be focused in order for window blur to fire when the iframe is interacted with. 
// There's still an issue that if user interacts outside of the page and then click iframe first without clicking page, the following logic won't run. But since the OP is only concerned about first click this shouldn't be a problem.
window.focus()

window.addEventListener("blur", () => {
  setTimeout(() => {
    if (document.activeElement.tagName === "IFRAME") {
      message.textContent = "clicked " + Date.now();
      console.log("clicked");
    }
  });
}, { once: true });
<div id="message"></div>
<iframe width="50%" height="300" src="//example.com"></iframe>

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

于 2014-04-22T22:09:22.527 回答
113

根据 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 悬停时,在包装 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 没有注册它。

再次感谢穆罕默德,非常有用的解决方案!

于 2011-11-12T00:18:54.817 回答
112

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

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

你可以在这里测试它:http: //jsfiddle.net/oqjgzsm0/

于 2015-08-21T10:31:06.757 回答
39

这样的事情可能吗?

不,您所能做的就是检测鼠标进入 iframe,并且可能(尽管不可靠)当它回来时(即试图找出在其他地方经过广告的指针与徘徊之间的区别在广告上)。

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

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

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

您可以尝试猜测,例如通过查看指针是否已经停止,猜测可能即将到来的点击。但这是完全不可靠的,如果你失败了,你就失去了一次点击。

于 2010-03-04T17:46:35.717 回答
37

以下代码将显示用户是否单击/悬停或移出 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 替换为您自己的链接。希望这会有所帮助。问候,莫。

于 2010-06-13T09:44:11.103 回答
12

刚刚找到这个解决方案......我试过了,我喜欢它......

适用于桌面和移动设备的跨域 iframe!

不知道是不是万无一失

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

快乐编码

于 2015-06-18T00:04:56.667 回答
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();
于 2013-02-14T23:52:16.850 回答
5

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

这是一个用于跟踪 iframe 上的点击的 jQuery 插件(当点击 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)
        }
    });
});
于 2013-04-03T17:29:41.443 回答
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>

于 2016-09-18T15:53:22.400 回答
4

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>

于 2016-05-10T09:07:14.983 回答
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>
于 2011-06-12T17:43:43.143 回答
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);
    });
});

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

于 2013-04-08T12:46:00.197 回答
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();
于 2014-01-29T17:58:31.090 回答
3

将上述答案与一次又一次点击的能力相结合,而无需在 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 );
    });
于 2019-09-20T06:44:31.530 回答
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
  }
});
于 2012-04-07T04:14:42.973 回答
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

于 2020-04-13T16:16:25.663 回答
0

我和一位同事,我们遇到了与 Brian Trumpsett 类似的问题,发现这个帖子很有帮助。我们的信息亭在 iframe 中有动画,我们需要跟踪页面活动以设置计时器。

正如这里所建议的,我们现在不是跟踪点击,而是在每次点击时检测焦点变化并将其改回以下代码在 macOS 上可以使用 Safari 和 Chrome,但不适用于 FireFox(为什么?):

var eventListener = window.addEventListener('blur', function() {
if (document.activeElement.classList && document.activeElement.classList[0] == 'contentiFrame') {
    refresh(); //function you want to call on click
            setTimeout(function(){ window.focus(); }, 1);
}
    window.removeEventListener('blur', eventListener );
});

问题是,在 Windows 上,它既不适用于 Chrome,也不适用于 FireFox,因此我们的信息亭无法正常工作。你知道为什么它不工作吗?你有解决方案让它在 Windows 上运行吗?

于 2021-03-21T14:13:36.073 回答
0

在那里找到:Detect Click into Iframe using JavaScript

=> 我们可以使用iframeTracker-jquery

$('.carousel-inner .item').each(function(e) {
    var item = this;
    var iFrame = $(item).find('iframe');
    if (iFrame.length &gt; 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 =&gt; OK');
            }
        });
        console.log('IFrameTrackingRegistred =&gt; OK');
    }
})
于 2018-01-20T23:43:30.000 回答
0

这是使用带有悬停+模糊和活动元素技巧的建议方法的解决方案,而不是任何库,只是纯 js。适用于 FF/Chrome。大部分方法与@Mohammed Radwan 提出的相同,除了我使用@zone117x 提出的不同方法来跟踪 FF 的 iframe 点击,因为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;
            });
    }
}
于 2018-10-04T11:46:42.200 回答
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();
            }
        });

代码很简单,blur事件检测点击iframe时失去焦点,并测试活动元素是否是iframe(如果你有几个iframe你可以知道谁被选中了)这种情况在你有宣传框架时经常出现.

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

于 2018-08-25T01:21:14.177 回答
0

我的方法类似于上面 Paul Draper 提出的方法。但是,它在 Firefox 中不起作用,因为 activeElement 没有及时更新以使代码执行。所以我们稍等一下。

如果您进入 iframe,这也会触发。对于我的用例,这很好,但你可以过滤那个按键。

addEventListenerOnIframe() {
    window.addEventListener('blur', this.onBlur);
}


onBlur = () => {
    setTimeout(() => {
        let activeElement = document.activeElement;
        let iframeElement = document.querySelector('iframe');
        if (activeElement === iframeElement) {
            
            //execute your code here

            //we only want to listen for the first time we click into the iframe
            window.removeEventListener('blur', this.onBlur);
        }
    }, 500);
};
于 2021-07-22T13:47:42.370 回答
0

假设-

  1. 您的脚本在 iframe 之外运行,但不在最外面的 window.top 窗口中。(对于最外面的窗口,其他模糊解决方案就足够了)
  2. 打开一个新页面以替换当前页面/新选项卡中的新页面,并将控制切换到新选项卡。

这适用于有源和无源iframe

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

如果打开一个新选项卡/卸载同一页面并且鼠标指针位于 iframe 内,则认为单击

于 2020-07-30T14:14:31.310 回答
-1

我相信您可以执行以下操作:

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

使用 jQuery 来实现这一点。

于 2011-07-12T17:10:54.150 回答