【问题标题】:Identifying window focus/blur events with iframes使用 iframe 识别窗口焦点/模糊事件
【发布时间】:2014-07-07 20:19:50
【问题描述】:

我正在尝试可靠地识别浏览器窗口/选项卡何时被激活和停用。通常,windowfocusblur 事件可以,但文档包含多个 iframe。
当 iframe 获得焦点时,主窗口会失去焦点,反之亦然,因此我们有以下焦点事件的可能性 [(none) 表示窗口/选项卡已停用]:

current focus       new focus               events
----------------------------------------------------------------------
window              (none)                  window:blur
window              iframe                  window:blur + iframe:focus
iframe              (none)                  iframe:blur
iframe              window                  iframe:blur + window:focus
iframe              another iframe          iframe:blur + iframe:focus
(none)              window                  window:focus
(none)              iframe                  iframe:focus

注册所有这些事件是没有问题的,如this fiddle所示。但每当我们从主窗口切换到 iframe 或反之亦然,或在两个 iframe 之间切换时,blurfocus 事件都会触发;他们会稍微延迟开火。

我担心这里的并发性,因为 blur 处理程序可以开始做一些事情,但它不应该开始,因为用户实际上只是在帧之间的某处切换了焦点。
示例:当页面当前不活动时,它应该定期执行一些 AJAX 请求。也就是说,它应该在用户停用选项卡时开始请求,并在再次激活时停止请求。因此,我们将一个函数绑定到启动请求的blur 事件。如果用户只是点击另一个 iframe,blur,然后不久,focus 就会被触发。但是blur 处理程序已经被触发,在它可以再次停止之前至少发出一个请求。

这就是我的问题:我怎样才能可靠地检测到用户何时实际(取消)激活包含 iframe 的浏览器窗口,而不会有因两个即时 @ 引起的误报风险987654337@ 和 focus 事件?

我写了一个半生不熟的解决方案,它在blur 事件之后使用超时来确定它之后是否有立即的focus 事件 (fiddle):

var active = false,
    timeout = 50, // ms
    lastBlur = 0,
    lastFocus = 0;

function handleBlur() {
    if (lastBlur - lastFocus > timeout) {
        active = false;
    }
}
function handleFocus() {
    if (lastFocus - lastBlur > timeout) {
        active = true;
    }
}

$(window).on('focus', function () {
    lastFocus = Date.now();
    handleFocus();
}).on('blur', function () {
    lastBlur = Date.now();
    window.setTimeout(handleBlur, timeout);
});

$('iframe').each(function () {
    $(this.contentWindow).on('focus', function () {
        lastFocus = Date.now();
        handleFocus();
    }).on('blur', function () {
        lastBlur = Date.now();
        window.setTimeout(handleBlur, timeout);
    });
});

但我相信这可能会带来很大的问题,尤其是在速度较慢的机器上。增加超时对我来说也是不可接受的,50 毫秒真的是我的痛苦阈值

有没有办法不依赖客户端足够快?

【问题讨论】:

  • 用focusout改变模糊怎么样? api.jquery.com/focusout
  • 如果您只需要在窗口焦点关闭时执行此操作,为什么还要在事件中包含“iframe”,而不仅仅是窗口?
  • @Cristo focusoutblur 的区别仅在于focusout 支持事件冒泡。也就是说,也会注册父元素的焦点丢失。但是,自己的window 是事件冒泡的限制,在这种情况下呈现focusoutblur 相同。查看this fiddle。如果焦点从主窗口(围绕 iframe)切换到 iframe,则主窗口的焦点将丢失,即使使用 focusout。这不符合我的要求,因为焦点仍在页面上(只是在该页面的 iframe 中)。
  • 我认为当你触发 iframe.blur 并且这个冒泡到窗口时可能会冒泡,导致它触发两次。我在最后一个小提琴中更好地看到了你的问题。从 iframe 到窗口点击时 window.focusout 触发

标签: javascript jquery iframe jquery-events onfocus


【解决方案1】:

我试图在没有轮询的情况下执行此操作,但 iframe 不会触发 onblur 事件(如果 iframe 处于焦点时浏览器窗口被停用,我不会触发任何事件),所以我最终需要轮询反正一半,但也许有人可以用这段代码弄清楚一些事情

function onFocus(){ console.log('browser window activated'); }
function onBlur(){ console.log('browser window deactivated'); }


var inter;
var iframeFocused;
window.focus();      // I needed this for events to fire afterwards initially  
addEventListener('focus', function(e){
    console.log('global window focused');
    if(iframeFocused){
        console.log('iframe lost focus');
        iframeFocused = false;
        clearInterval(inter);
    }
    else onFocus();
});

addEventListener('blur', function(e){
    console.log('global window lost focus');
    if(document.hasFocus()){
        console.log('iframe focused');
        iframeFocused = true;
        inter = setInterval(()=>{
            if(!document.hasFocus()){
                console.log('iframe lost focus');
                iframeFocused = false;
                onBlur();
                clearInterval(inter);
            }
        },100);
    }
    else onBlur();
});

【讨论】:

  • 谢谢,帮了大忙。但是,为了让“onFocus()”函数也能正常工作,那么情况是“iFrame 聚焦,离开选项卡,返回选项卡”我不得不添加 window.focus();在 onBlur() 之前的区间内。
【解决方案2】:

您可以轮询 document.hasFocus() 值,如果 iframe 或主窗口被聚焦,则该值应为 true

setInterval(function checkFocus(){
    if( checkFocus.prev == document.hasFocus() ) return;  
    if(document.hasFocus()) onFocus();
    else onBlur();                    
    checkFocus.prev = document.hasFocus();  
},100);

function onFocus(){ console.log('browser window activated') }
function onBlur(){ console.log('browser window deactivated') }

【讨论】:

    猜你喜欢
    • 2012-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-12
    • 1970-01-01
    • 2018-03-15
    • 1970-01-01
    相关资源
    最近更新 更多