Javascript 使用 ALT+TAB 切换程序/窗口或单击任务栏时,不触发可见性更改事件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28993157/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
visibilitychange event is not triggered when switching program/window with ALT+TAB or clicking in taskbar
提问by agbb
The problem is with the behaviour of the event "visibilitychange".
问题在于事件“visibilitychange”的行为。
It's triggered:- When I switch to a different tab inside the browser window.
它被触发:- 当我切换到浏览器窗口内的不同选项卡时。
- When I click in minimize / restore buttons for the browser window.
- 当我单击浏览器窗口的最小化/恢复按钮时。
(this is ok)
(还行吧)
It's not triggered:- When I switch to a different window/program using ALT+TAB.
它不会被触发:- 当我使用 ALT+TAB 切换到不同的窗口/程序时。
- When I switch to a different window/program clicking on taskbar.
- 当我切换到不同的窗口/程序时,单击任务栏。
(this SHOULD trigger, because, just like when minimizing, the window's visibility may change)
(这应该触发,因为就像最小化时一样,窗口的可见性可能会改变)
W3 Page Visibility API Documentation: http://www.w3.org/TR/page-visibility/
W3 页面可见性 API 文档:http: //www.w3.org/TR/page-visibility/
There is no definition of "page visibility" regarding ALT+TAB/program switching in the spec sheet. I'm guessing it has something to do in between the OS and the Browser.
在规格表中没有关于ALT+ TAB/program 切换的“页面可见性”定义。我猜它在操作系统和浏览器之间有关系。
TESTED IN
测试
- Browsers: Chrome 40.0.2214.115 m / Firefox 36.0.1 / Internet Explorer 11.0.9600.17107
- OS: Windows 8.1
- 浏览器:Chrome 40.0.2214.115 m / Firefox 36.0.1 / Internet Explorer 11.0.9600.17107
- 操作系统:Windows 8.1
Is there a workaround to fix this behaviour? The implementation is fairly simple, I listen to the "visibilitychange" event using jQuery, and then in its callback, I check for the value of "document.visibilityState", but the problem is that the event is not firing when expected.
是否有解决此行为的解决方法?实现相当简单,我使用 jQuery 监听“visibilitychange”事件,然后在它的回调中,我检查“document.visibilityState”的值,但问题是该事件没有按预期触发。
$(document).on('visibilitychange', function() {
if(document.visibilityState == 'hidden') {
// page is hidden
} else {
// page is visible
}
});
This can be done without jQuery too, but the ALT+TABand taskbar switch hide/show expected behaviour is still missing:
这也可以在没有 jQuery 的情况下完成,但仍然缺少ALT+TAB和任务栏切换隐藏/显示预期行为:
if(document.addEventListener){
document.addEventListener("visibilitychange", function() {
// check for page visibility
});
}
I've also tried the ifvisible.js module (https://github.com/serkanyersen/ifvisible.js) but the behaviour is the same.
我也试过 ifvisible.js 模块(https://github.com/serkanyersen/ifvisible.js),但行为是一样的。
ifvisible.on('blur', function() {
// page is hidden
});
ifvisible.on('focus', function() {
// page is visible
});
I haven't tested in other browsers because if I can't make it work in Chrome on Windows I really don't care about the other browsers yet.
我没有在其他浏览器中测试过,因为如果我不能让它在 Windows 上的 Chrome 中工作,我真的不关心其他浏览器。
Any help or suggestions?
任何帮助或建议?
UPDATE
更新
I tried using different vendor prefixes for the event name (visibilitychange, webkitvisibilitychange, mozvisibilitychange, msvisibilitychange) but but still the event is not triggered when I switch to a different program in the taskbar or ALT+TAB, or even if I open the start menu thing in windows with the windows key, which covers the whole screen.
我尝试为事件名称(visibilitychange、webkitvisibilitychange、mozvisibilitychange、msvisibilitychange)使用不同的供应商前缀,但是当我切换到任务栏或ALT+ 中的其他程序时,事件仍未触发TAB,或者即使我打开开始菜单windows键,覆盖整个屏幕。
I can reproduce the exact same issue in Chrome, Firefox and Internet Explorer.
我可以在 Chrome、Firefox 和 Internet Explorer 中重现完全相同的问题。
UPDATE #2
更新 #2
Here'sa roundup post I wrote for this issue and a workaround in pure Javascript to solve the encountered problems.
这是我为这个问题写的一篇综述文章,以及用纯 Javascript 解决遇到的问题的解决方法。
UPDATE #3
更新 #3
Edited to include a copy of the sourced blog post. (see accepted answer)
编辑以包含来源博客文章的副本。(见接受的答案)
采纳答案by agbb
Here'sa roundup post I wrote for this issue and a workaround in pure javascript to solve the encountered problems.
这是我为这个问题写的综述文章和纯 javascript 中解决遇到的问题的解决方法。
Edited to include a copy of the sourced blog post:
编辑以包含来源博客文章的副本:
In any kind of javascript application we develop there may be a feature or any change in the application which reacts according to the current user visibility state, this could be to pause a playing video when the user ALT+TABs to a different window, tracking stats about how the users interact with our application, how often does him switch to a different tab, how long does it take him to return and a lot of performance improvements that can benefit from this kind of API.
在我们开发的任何类型的 javascript 应用程序中,应用程序中可能有一个功能或任何更改,它会根据当前用户的可见性状态做出反应,这可能是当用户 ALT+TABs 到不同的窗口时暂停播放视频,跟踪统计信息关于用户如何与我们的应用程序交互、他切换到不同选项卡的频率、他返回需要多长时间以及可以从这种 API 中受益的许多性能改进。
The Page Visibility API provides us with two top-level attributes: document.hidden (boolean) and document.visibilityState (which could be any of these strings: “hidden”, “visible”, “prerender”, “unloaded”). This would not be not good enough without an event we could listen to though, that's why the API also provides the useful visibilitychange event.
Page Visibility API 为我们提供了两个顶级属性:document.hidden(布尔值)和 document.visibilityState(可以是以下字符串中的任何一个:“hidden”、“visible”、“prerender”、“unloaded”)。如果没有我们可以监听的事件,这还不够好,这就是 API 还提供有用的可见性更改事件的原因。
So, here's a basic example on how we could take action on a visibility change:
因此,这里有一个基本示例,说明我们如何对可见性更改采取行动:
function handleVisibilityChange() {
if(document.hidden) {
// the page is hidden
} else {
// the page is visible
}
}
document.addEventListener("visibilitychange", handleVisibilityChange, false);
We could also check for document.visibilityState value.
我们还可以检查 document.visibilityState 值。
Dealing with vendor issues George Berkeley by John Smibert
处理供应商问题 George Berkeley by John Smibert
Some of the implementations on some browsers still need that the attributes or even the event name is vendor-prefixed, this means we may need to listen to the msvisibilitychange event or check for the document.webkitHidden or the document.mozHidden attributes. In order to do so, we should check if any vendor-prefixed attribute is set, and once we know which one is the one used in the current browser (only if there's the need for a prefix), we can name the event and attributes properly.
一些浏览器上的一些实现仍然需要属性甚至事件名称是供应商前缀的,这意味着我们可能需要监听 msvisibilitychange 事件或检查 document.webkitHidden 或 document.mozHidden 属性。为此,我们应该检查是否设置了任何供应商前缀的属性,一旦我们知道当前浏览器中使用的是哪个(仅当需要前缀时),我们就可以命名事件和属性适当地。
Here's an example approach on how to handle these prefixes:
以下是有关如何处理这些前缀的示例方法:
var browserPrefixes = ['moz', 'ms', 'o', 'webkit'];
// get the correct attribute name
function getHiddenPropertyName(prefix) {
return (prefix ? prefix + 'Hidden' : 'hidden');
}
// get the correct event name
function getVisibilityEvent(prefix) {
return (prefix ? prefix : '') + 'visibilitychange';
}
// get current browser vendor prefix
function getBrowserPrefix() {
for (var i = 0; i < browserPrefixes.length; i++) {
if(getHiddenPropertyName(browserPrefixes[i]) in document) {
// return vendor prefix
return browserPrefixes[i];
}
}
// no vendor prefix needed
return null;
}
// bind and handle events
var browserPrefix = getBrowserPrefix();
function handleVisibilityChange() {
if(document[getHiddenPropertyName(browserPrefix )]) {
// the page is hidden
console.log('hidden');
} else {
// the page is visible
console.log('visible');
}
}
document.addEventListener(getVisibilityEvent(browserPrefix), handleVisibilityChange, false);
Other issues There is a challenging issue around the “Page Visibility” definition: how to determine if the application is visible or not if the window focus is lost for another window, but not the actual visibility on the screen? what about different kinds of visibility lost, like ALT+TAB, WIN/MAC key (start menu / dash), taskbar/dock actions, WIN+L (lock screen), window minimize, window close, tab switching. What about the behaviour on mobile devices?
其他问题 围绕“页面可见性”定义存在一个具有挑战性的问题:如果另一个窗口的窗口焦点丢失,而不是屏幕上的实际可见性,如何确定应用程序是否可见?不同类型的可见性丢失怎么样,比如 ALT+TAB、WIN/MAC 键(开始菜单/破折号)、任务栏/停靠操作、WIN+L(锁定屏幕)、窗口最小化、窗口关闭、选项卡切换。移动设备上的行为呢?
There's lots of ways in which we may lose or gain visibility and a lot of possible interactions between the browser and the OS, therefore I don't think there's a proper and complete “visible page” definition in the W3C spec. This is the definition we get for the document.hidden attribute:
我们可能会以多种方式失去或获得可见性以及浏览器和操作系统之间的许多可能的交互,因此我认为 W3C 规范中没有正确且完整的“可见页面”定义。这是我们为 document.hidden 属性得到的定义:
HIDDEN ATTRIBUTE On getting, the hidden attribute MUST return true if the Document contained by the top level browsing context (root window in the browser's viewport) [HTML5] is not visible at all. The attribute MUST return false if the Document contained by the top level browsing context is at least partially visible on at least one screen.
隐藏属性在获取时,如果顶级浏览上下文(浏览器视口中的根窗口)[HTML5] 中包含的文档根本不可见,则隐藏属性必须返回 true。如果顶级浏览上下文包含的文档在至少一个屏幕上至少部分可见,则该属性必须返回 false。
If the defaultView of the Document is null, on getting, the hidden attribute MUST return true.
如果 Document 的 defaultView 为 null,则在获取时,隐藏属性必须返回 true。
To accommodate accessibility tools that are typically full screen but still show a view of the page, when applicable, this attribute MAY return false when the User Agent is not minimized but is fully obscured by other applications.
为了适应通常是全屏但仍显示页面视图的辅助工具,如果适用,当用户代理未最小化但被其他应用程序完全遮挡时,此属性可能返回 false。
I've found several inconsistencies on when the event is actually fired, for example (Chrome 41.0.2272.101 m, on Windows 8.1) the event is not fired when I ALT+TAB to a different window/program nor when I ALT+TAB again to return, but it IS fired if I CTRL+TAB and then CTRL+SHIFT+TAB to switch between browser tabs. It's also fired when I click on the minimize button, but it's not fired if the window is not maximized and I click my editor window which is behing the browser window. So the behaviour of this API and it's different implementations are still obscure.
我发现在实际触发事件时存在一些不一致的情况,例如(Chrome 41.0.2272.101 m,在 Windows 8.1 上)当我 ALT+TAB 到不同的窗口/程序时,或者我再次 ALT+TAB 时都不会触发事件返回,但如果我 CTRL+TAB 然后 CTRL+SHIFT+TAB 在浏览器选项卡之间切换,它会被触发。当我点击最小化按钮时它也会被触发,但是如果窗口没有最大化并且我点击浏览器窗口后面的编辑器窗口,它不会被触发。所以这个 API 的行为及其不同的实现仍然是模糊的。
A workaround for this, is to compensate taking advantage of the better implemented focus and blur events, and making a custom approach to the whole “Page Visibility” issue using an internal flag to prevent multiple executions, this is what I've come up with:
对此的解决方法是利用更好地实现的焦点和模糊事件进行补偿,并使用内部标志对整个“页面可见性”问题进行自定义方法以防止多次执行,这就是我提出的:
var browserPrefixes = ['moz', 'ms', 'o', 'webkit'],
isVisible = true; // internal flag, defaults to true
// get the correct attribute name
function getHiddenPropertyName(prefix) {
return (prefix ? prefix + 'Hidden' : 'hidden');
}
// get the correct event name
function getVisibilityEvent(prefix) {
return (prefix ? prefix : '') + 'visibilitychange';
}
// get current browser vendor prefix
function getBrowserPrefix() {
for (var i = 0; i < browserPrefixes.length; i++) {
if(getHiddenPropertyName(browserPrefixes[i]) in document) {
// return vendor prefix
return browserPrefixes[i];
}
}
// no vendor prefix needed
return null;
}
// bind and handle events
var browserPrefix = getBrowserPrefix(),
hiddenPropertyName = getHiddenPropertyName(browserPrefix),
visibilityEventName = getVisibilityEvent(browserPrefix);
function onVisible() {
// prevent double execution
if(isVisible) {
return;
}
// change flag value
isVisible = true;
console.log('visible}
function onHidden() {
// prevent double execution
if(!isVisible) {
return;
}
// change flag value
isVisible = false;
console.log('hidden}
function handleVisibilityChange(forcedFlag) {
// forcedFlag is a boolean when this event handler is triggered by a
// focus or blur eventotherwise it's an Event object
if(typeof forcedFlag === "boolean") {
if(forcedFlag) {
return onVisible();
}
return onHidden();
}
if(document[hiddenPropertyName]) {
return onHidden();
}
return onVisible();
}
document.addEventListener(visibilityEventName, handleVisibilityChange, false);
// extra event listeners for better behaviour
document.addEventListener('focus', function() {
handleVisibilityChange(true);
}, false);
document.addEventListener('blur', function() {
handleVisibilityChange(false);
}, false);
window.addEventListener('focus', function() {
handleVisibilityChange(true);
}, false);
window.addEventListener('blur', function() {
handleVisibilityChange(false);
}, false);
I welcome any feedback on this workaround. Some other great sources for ideas on this subject:
我欢迎对此解决方法的任何反馈。关于这个主题的一些其他重要的想法来源:
Using the Page Visibility API Using PC Hardware more efficiently in HTML5: New Web Performance APIs, Part 2 Introduction to the Page Visibility API Conclusion The technologies of the web are continuously evolving, we're still recovering from a dark past where tables where the markup king, where semantics didn't mattered, and they weren't any standards around how a browser should render a page.
使用页面可见性 API 在 HTML5 中更有效地使用 PC 硬件:新的 Web 性能 API,第 2 部分页面可见性 API 简介 结论 Web 技术不断发展,我们仍在从黑暗的过去中恢复过来国王,语义无关紧要,并且它们不是浏览器应该如何呈现页面的任何标准。
It's important we push these new standards forward, but sometimes our development requirements make us still need to adapt to these kind of transitions, by handling vendor prefixes, testing in different browsers and differents OSs or depend on third-party tools to properly identify this differences.
我们推动这些新标准很重要,但有时我们的开发需求使我们仍然需要通过处理供应商前缀、在不同浏览器和不同操作系统中测试或依赖第三方工具来正确识别这种差异来适应这些类型的转换.
We can only hope for a future where the W3C specifications are strictly revised, strictly implemented by the browser developer teams, and maybe one day we will have a common standard for all of us to work with.
我们只能希望未来 W3C 规范得到严格修订,由浏览器开发团队严格执行,也许有一天我们会有一个共同的标准供我们所有人使用。
As for the Page Visibility API let's just kinda cite George Berkeley and say that:
至于页面可见性 API,让我们引用 George Berkeley 的话说:
“being visible” is being perceived.
“可见”就是被感知。
回答by Julien Kronegg
A working solution is proposed described here: https://stackoverflow.com/a/9502074/698168. It uses a combination of the W3C Page Visibility API, blur/focus and mouse movements. Hidden HTML pages related to Alt+Tab are identified in a probabilistic way (i.e. you cannot determine if your page is hidden with 100% accuracy).
此处描述了一个工作解决方案:https: //stackoverflow.com/a/9502074/698168。它结合了 W3C 页面可见性 API、模糊/焦点和鼠标移动。与 Alt+Tab 相关的隐藏 HTML 页面以概率方式识别(即您无法确定您的页面是否以 100% 的准确度隐藏)。
回答by anjaneyulubatta505
we can do like below when switching between tabs and switching between applications
在选项卡之间切换和在应用程序之间切换时,我们可以执行以下操作
var pageVisible = true;
function handleVisibilityChange() {
if (document.hidden) {
pageVisible = false;
} else {
pageVisible = true;
}
console.log("handleVisibilityChange")
console.log("pageVisible", pageVisible)
// some function call
}
document.addEventListener("visibilitychange", handleVisibilityChange, false);
window.addEventListener('focus', function() {
pageVisible = true;
// some function call
}, false);
window.addEventListener('blur', function() {
pageVisible = false;
// some function call
}, false);
回答by vishal kokate
There's a very simple solution to this I have come across.
我遇到了一个非常简单的解决方案。
You just need to pass false to the useCapture while attaching an event listener to the document. Works like a charm!
您只需要在将事件侦听器附加到文档时将 false 传递给 useCapture。奇迹般有效!
document.addEventListener('visibilitychange', function () {
// code goes here
}, false)

