检测 iframe 何时获得或失去焦点

问题描述 投票:0回答:11

检测 iframe 何时获得或失去焦点(即是否会接收键盘事件)的正确方法是什么?以下内容在 Fx4 中不起作用:

var iframe = /* my iframe */;
iframe.addEventListener("focus", function() { /* never gets called */ }, false);
javascript html dom dom-events
11个回答
28
投票

您可以轮询“document.activeElement”以确定它是否与 iframe 匹配。轮询并不理想,但它有效:

function checkFocus() {
  if(document.activeElement == document.getElementsByTagName("iframe")[0]) {
    console.log('iframe has focus');
  } else {
    console.log('iframe not focused');
  }
}

window.setInterval(checkFocus, 1000); 

12
投票

我知道它很旧,但我也遇到了同样的问题。

我最终使用了这段小代码:

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

6
投票

事实证明这根本不可能。我必须更改页面的逻辑,以避免在 iframe 具有焦点时进行跟踪。


4
投票

如何检查 iframe 何时被点击进入或退出以及悬停状态。

注意:我强烈建议您不要选择轮询方法,而采用诸如此类的事件驱动方法。


免责声明

无法直接在 iframe 上使用

focus
blur
事件,但您可以在
window
上使用它们来提供检查
document.activeElement
的事件驱动方法。这样你就可以完成你所追求的事情。

虽然现在已经是 2018 年了,但我的代码正在 GTM 中实现,并尝试跨浏览器兼容回 IE 11。这意味着如果您使用更新的 ES/ECMAScript 功能,代码会更高效。


设置

我将进一步采取几个步骤来表明我们还可以获取 iframe 的

src
属性并确定它是否正在悬停。

代码

理想情况下,您需要将其放入文档就绪事件中,或者至少将其封装起来,以便变量不是全局的[也许使用 IIFE]。我没有将其包装在准备好的文档中,因为它是由 GTM 处理的。它还可能取决于您将其放置在何处或如何加载它,例如在页脚中。

https://jsfiddle.net/9285tbsm/9/

我在 JSFiddle 预览中注意到它已经是一个 iframe,有时您必须在事件开始捕获之前先将其聚焦。其他问题可能是您的浏览器窗口尚未聚焦。

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

3
投票

我通过使用

contentWindow
而不是
contentDocument
解决了这个问题。
contentWindow
的好处是

  1. 它也适用于用户单击另一个窗口(另一个应用程序)或另一个浏览器选项卡的情况。如果使用
    activeElement
    ,如果用户单击整个窗口以外的位置以转到另一个应用程序,则该逻辑仍然认为 iframe 处于焦点,而事实并非如此
  2. 我们根本不需要进行民意调查和做
    setInterval
    。这使用正常的
    addEventListener
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
}


1
投票

这个解决方案在移动设备和桌面上都适用于我:

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

0
投票

解决方案是在父页面上注入一个 javascript 事件,如下所示:

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

0
投票

一个紧凑的函数,接受您想要在 iframe 获得或失去焦点时运行的回调。

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

0
投票

这是检测 iframe 何时获得或失去焦点的代码

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

0
投票

2024 iOS 更新

我最近遇到了一种情况,我需要检测页面上的许多 iframe 之一何时接收或失去焦点。 iframe 的内容来自不同的域,我对它们的控制权为零。

我首先尝试了一种方法,该方法依赖于向主窗口添加“模糊”和“焦点”事件的事件侦听器,用零计时器触发函数调用,然后检查

document.activeElement
是否与任何 iframe 元素匹配。这似乎适用于 Windows、OSX 和 Android 的所有浏览器。 (Firefox 要求使用 0 秒计时器进行函数调用)

我不明白为什么,但在 iOS 上的 Safari 和 Chrome 上,主窗口“模糊”事件只会发出一次。之后它就停止工作了。

我可以让代码在所有平台上工作的唯一方法是切换到基于计时器的方法,在该方法中,我每 300 毫秒将

document.activeElement
与每个 iframe 元素和 activeElement 的先前值进行比较,以检查焦点是否在主窗口和 iframe。

我希望这可以节省一些人的时间,因为我最终浪费了很多时间尝试在 Windows 电脑上调试 iOS 问题。


-1
投票

这可能有用

document.addEventListener('click', function(event) {
  var frame= document.getElementById("yourFrameID");

  var isClickInsideFrame = frame.contains(event.target);

  if (!isClickInsideFrame ) {
    //exec code
  }

});
© www.soinside.com 2019 - 2024. All rights reserved.