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:
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 focus
ing document.body
), any window
focus
handlers don't fire. And since we're return
ing 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.