Detecting when an iframe gets or loses focus
What's the correct way of detecting when an iframe gets or loses focus (i.e. will or will not receive keyboard events)? The following is not working in Fx4:
var iframe = /* my iframe */;
iframe.addEventListene开发者_C百科r("focus", function() { /* never gets called */ }, false);
You can poll "document.activeElement" to determine if it matches the iframe. Polling isn't ideal, but it works:
function checkFocus() {
if(document.activeElement == document.getElementsByTagName("iframe")[0]) {
console.log('iframe has focus');
} else {
console.log('iframe not focused');
}
}
window.setInterval(checkFocus, 1000);
i know it's old, but i also had the same problem.
i ended up using this little pice of code:
$(document).on('focusout', function(){
setTimeout(function(){
// using the 'setTimout' to let the event pass the run loop
if (document.activeElement instanceof HTMLIFrameElement) {
// Do your logic here..
}
},0);
});
Turns out it's not really possible. I had to change the logic of my page to avoid the need of tracking if the iframe has focus.
How to check when an iframe has been clicked in or out of as well as hover-state.
Note: I would highly recommend you don't choose a polling method and go with an event driven method such as this.
Disclaimer
It is not possible to use the focus
or blur
events directly on an iframe but you can use them on the window
to provide an event driven method of checking the document.activeElement
. Thus you can accomplish what you're after.
Although we're now in 2018, my code is being implemented in GTM and tries to be cross browser compatible back to IE 11. This means there's more efficient code if you're utilizing newer ES/ECMAScript features.
Setup
I'm going to take this a few steps further to show that we can also get the iframe's src
attribute as well as determine if it's being hovered.
Code
You would ideally need to put this in a document ready event, or at least encapsulate it so that the variables aren't global [maybe use an IIFE]. I did not wrap it in a document ready because it's handled by GTM. It may also depend where you place this or how you're loading it such as in the footer.
https://jsfiddle.net/9285tbsm/9/
I have noticed in the JSFiddle preview that it's already an iframe, sometimes you have to focus it first before events start to capture. Other issues can be that your browser window isn't yet focused either.
// Helpers
var iframeClickedLast;
function eventFromIframe(event) {
var el = event.target;
return el && el.tagName && el.tagName.toLowerCase() == 'iframe';
}
function getIframeSrc(event) {
var el = event.target;
return eventFromIframe(event) ? el.getAttribute('src') : '';
}
// Events
function windowBlurred(e) {
var el = document.activeElement;
if (el.tagName.toLowerCase() == 'iframe') {
console.log('Blurred: iframe CLICKED ON', 'SRC:', el.getAttribute('src'), e);
iframeClickedLast = true;
}
else {
console.log('Blurred', e);
}
}
function windowFocussed(e) {
if (iframeClickedLast) {
var el = document.activeElement;
iframeClickedLast = false;
console.log('Focussed: iframe CLICKED OFF', 'SRC:', el.getAttribute('src'), e);
}
else {
console.log('Focussed', e);
}
}
function iframeMouseOver(e) {
console.log('Mouse Over', 'SRC:', getIframeSrc(e), e);
}
function iframeMouseOut(e) {
console.log('Mouse Out', 'SRC:', getIframeSrc(e), e);
}
// Attach Events
window.addEventListener('focus', windowFocussed, true);
window.addEventListener('blur', windowBlurred, true);
var iframes = document.getElementsByTagName("iframe");
for (var i = 0; i < iframes.length; i++) {
iframes[i].addEventListener('mouseover', iframeMouseOver, true);
iframes[i].addEventListener('mouseout', iframeMouseOut, true);
}
This solution is working for me on both mobile and desktop:
;(function pollForIframe() {
var myIframe = document.querySelector('#my_iframe');
if (!myIframe) return setTimeout(pollForIframe, 50);
window.addEventListener('blur', function () {
if (document.activeElement == myIframe) {
console.log('myIframe clicked!');
}
});
})();
I have solved this by using contentWindow
instead of contentDocument
.
The good thing about contentWindow
is
- it works also in case user clicks another window (another application) or another browser tab. If using
activeElement
, if user clicks away from the entire window to go to another application, then that logic still think the iframe is in focus, while it is not - and we don't need to poll and do a
setInterval
at all. This uses the normaladdEventListener
let iframe = document.getElementsByTagName("iframe")[0];
// or whatever way you do to grab that iFrame, say you have an `id`, then it's even more precise
if(iframe){
iframeWindow = iframe.contentWindow;
iframeWindow.addEventListener('focus', handleIframeFocused);
iframeWindow.addEventListener('blur', handleIframeBlurred);
}
function handleIframeFocused(){
console.log('iframe focused');
// Additional logic that you need to implement here when focused
}
function handleIframeBlurred(){
console.log('iframe blurred');
// Additional logic that you need to implement here when blurred
}
The solution is to inject a javascript event on the parent page like this :
var script = document.createElement('script');
script.type = 'text/javascript';
script.innerHTML =
"document.addEventListener('click', function()" +
"{ if(document.getElementById('iframe')) {" +
// What you want
"}});";
head.appendChild(script);
Here is the code to Detecting when an iframe gets or loses focus
// This code can be used to verify Iframe gets focus/loses.
function CheckFocus(){
if (document.activeElement.id == $(':focus').context.activeElement.id) {
// here do something
}
else{
//do something
}
}
A compact function that accepts callbacks you want to run when iframe gets or loses focus.
/* eslint-disable no-unused-vars */
export default function watchIframeFocus(onFocus, onBlur) {
let iframeClickedLast;
function windowBlurred(e) {
const el = document.activeElement;
if (el.tagName.toLowerCase() == 'iframe') {
iframeClickedLast = true;
onFocus();
}
}
function windowFocussed(e) {
if (iframeClickedLast) {
iframeClickedLast = false;
onBlur();
}
}
window.addEventListener('focus', windowFocussed, true);
window.addEventListener('blur', windowBlurred, true);
}
This might work
document.addEventListener('click', function(event) {
var frame= document.getElementById("yourFrameID");
var isClickInsideFrame = frame.contains(event.target);
if (!isClickInsideFrame ) {
//exec code
}
});
精彩评论