Tracking focus on cross-origin iframe

2019-08-20 09:43发布

I have a web app with an embedded video within an iframe, typically from a cross-origin source (e.g. YouTube). I currently track focus on window for logging purposes. However, since iframes are not children of window, when the user clicks into the iframe, window blurs, stopping my logs though the user is still viewing the page. How can I track focus to this cross-origin iframe?

1条回答
戒情不戒烟
2楼-- · 2019-08-20 10:12

tl;dr - you can't track focus on the iframe, at least not directly. But there are other sources of information that can be useful enough.

Since the iframe is cross-origin, that immediately rules out accessing its focus state directly, attaching any event handlers, or posting any messages. However, you can use document.body.activeElement to see if the user clicked on the iframe as opposed to another tab/window. With that knowledge, this hack is possible:

const handleLeave = () => {
  const { activeElement } = document;
  const iframeIsActiveElement = activeElement && activeElement.tagName === 'IFRAME';

  if (iframeIsActiveElement) {
    // timeout necessary to not blur the iframe too quickly
    setTimeout(() => activeElement.blur(), 0);
    return;
  }

  doBlurStuff();
};

window.addEventListener('blur', handleLeave);

So when window blurs, we're checking to see if the user clicked on the iframe. If they did, we're going to blur the iframe (the user's action will have already occurred), which returns focus to document.body. For unknown reasons (probably either that it happens too quickly, or that we're not explicitly focusing document.body), any window focus handlers don't fire. And since we're returning early, doBlurStuff also doesn't fire.

One tradeoff: since we're focus-jacking, this has accessibility and UX concerns. The user will not be able to use keyboard events for the iframe, since it will never be able to hold focus. This tradeoff may not be worth it for many usages.

查看更多
登录 后发表回答