问题在于事件"visibilitychange"的行为。
它被触发:-当我切换到浏览器窗口内的另一个选项卡时。
- 当我点击浏览器窗口的最小化/恢复按钮时
(这是可以的)
它没有被触发:-当我使用ALT+TAB切换到另一个窗口/程序时。
- 当我切换到不同的窗口/程序时,点击任务栏
(这应该触发,因为就像最小化时一样,窗口的可见性可能会改变)
W3页面可见性API文档:http://www.w3.org/TR/page-visibility/
规格表中没有关于ALT+TAB/程序切换的"页面可见性"定义。我猜这与操作系统和浏览器之间的关系有关
测试输入
- 浏览器:Chrome浏览器40.0.2214.115米/Firefox 36.0.1/Internet Explorer 11.0.9600.17107
- 操作系统:Windows 8.1
是否有解决此行为的方法?实现相当简单,我使用jQuery监听"visibilitychange"事件,然后在其回调中,我检查"document.visibilityState"的值,但问题是该事件没有按预期触发。
$(document).on('visibilitychange', function() {
if(document.visibilityState == 'hidden') {
// page is hidden
} else {
// page is visible
}
});
这也可以在没有jQuery的情况下完成,但ALT+TAB和任务栏开关隐藏/显示预期行为仍然缺失:
if(document.addEventListener){
document.addEventListener("visibilitychange", function() {
// check for page visibility
});
}
我还尝试了ifvisible.js模块(https://github.com/serkanyersen/ifvisible.js)但行为是一样的。
ifvisible.on('blur', function() {
// page is hidden
});
ifvisible.on('focus', function() {
// page is visible
});
我还没有在其他浏览器中进行测试,因为如果我不能在Windows上的Chrome中运行,我真的不在乎其他浏览器。
有什么帮助或建议吗?
更新
我尝试使用不同的供应商前缀作为事件名称(visibilitychange、webkitsvisibility change、mozvisibiliTY change、msvisibilities change),但当我切换到任务栏中的不同程序或ALT+TAB时,或者即使我用windows键打开windows中的开始菜单,也不会触发该事件,因为它覆盖了整个屏幕。
我可以在Chrome、Firefox和Internet Explorer中复制完全相同的问题。
更新#2
这是我为这个问题写的一篇综述文章,以及用纯Javascript解决遇到的问题的方法。
更新#3
编辑后包含来源博客文章的副本。(见公认答案)
这是我为这个问题写的一篇综述文章,以及用纯JavaScript解决遇到的问题的方法。
编辑后包含来源博客文章的副本:
在我们开发的任何类型的javascript应用程序中,都可能存在功能或应用程序中根据当前用户可见性状态,这可能是暂停播放视频当用户ALT+TAB切换到另一个窗口时,跟踪有关如何用户与我们的应用程序交互,他多久切换一次另一张账单,他需要多长时间才能回来,还有很多可以从这种API中获益的性能改进。
页面可见性API为我们提供了两个顶级属性:document.hidden(布尔值)和document.visibilityState(可以是这些字符串中的任何一个:"隐藏"、"可见"、"预呈现"、"卸载")。如果没有我们可以聆听的活动,这是不够的不过,这就是为什么API还提供了有用的可见性更改事件
因此,这里有一个关于我们如何对可见性采取行动的基本示例更改:
function handleVisibilityChange() { if(document.hidden) { // the page is hidden } else { // the page is visible } } document.addEventListener("visibilitychange", handleVisibilityChange, false);
我们还可以检查document.visibilityState值。
处理供应商问题George Berkeley著John Smibert
某些浏览器上的一些实现仍然需要属性,甚至事件名称都以供应商为前缀,这意味着我们可能需要监听msvisibilitychange事件或检查document.webkitHidden或document.mozHidden属性。整齐为此,我们应该检查是否设置了任何以供应商为前缀的属性,并且一旦我们知道当前浏览器中使用的是哪一个(仅当需要前缀),我们可以命名事件和属性正确地
下面是一个关于如何处理这些前缀的示例方法:
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);
其他问题围绕"页面可见性"存在一个具有挑战性的问题定义:如何确定应用程序是否可见另一个窗口的窗口焦点丢失,但不是实际窗口屏幕上的可见性?不同的能见度如何丢失,如ALT+TAB、WIN/MAC键(开始菜单/仪表板)、任务栏/停靠操作,WIN+L(锁定屏幕),窗口最小化,窗口关闭,选项卡切换。移动设备上的行为如何?
我们可能会以多种方式失去或获得知名度浏览器和操作系统之间可能的交互,因此我不要认为在W3C规范。这是我们为文档得到的定义。idden属性:
HIDDEN ATTRIBUTE获取时,如果顶级浏览上下文(根窗口)所包含的文档在浏览器的视口中)[HTML5]根本不可见。这个如果顶层包含的文档,则属性必须返回false浏览上下文在至少一个屏幕上至少部分可见。
如果文档的defaultView为null,则在获取时,隐藏属性必须返回true。
为了适应通常是全屏的可访问性工具仍然显示页面的视图,如果适用,此属性可能当用户代理未最小化但已完全最小化时,返回false被其他应用程序遮挡。
我发现了一些关于事件实际发生时间的不一致之处例如,激发(Chrome 41.0.2272.101米,在Windows 8.1上)该事件当我ALT+TAB到不同的窗口/程序时,或者当我再次ALT+TAB返回,但如果我CTRL+TAB然后CTRL+SHIFT+TAB可在浏览器选项卡之间切换。当我单击最小化按钮,但如果窗口没有最大化,然后单击浏览器后面的编辑器窗口窗所以这个API的行为和它是不同的实现仍然模糊不清。
解决方法是利用更好的实现了焦点和模糊事件,并对使用内部标志防止整个"页面可见性"问题多次执行,这就是我想到的:
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);
我欢迎对此解决方法的任何反馈。其他一些好消息来源关于这个主题的想法:
使用页面可见性API在中更有效地使用PC硬件HTML5:新的Web性能API,第2部分页面简介可见性API结论网络技术不断发展不断发展,我们仍在从黑暗的过去中恢复标记之王,语义并不重要,它们也不重要关于浏览器应该如何呈现页面的标准。
我们推动这些新标准向前发展很重要,但有时我们开发需求使我们仍然需要适应转换,通过处理供应商前缀,在不同的浏览器和差异操作系统或依赖第三方工具识别这种差异。
我们只能寄希望于W3C规范的未来严格修订,由浏览器开发团队严格执行,也许有一天我们会有一个共同的工作标准具有
至于页面可见性API,让我们引用George Berkeley然后说:
"可见"就是被感知。
这里介绍了一个工作解决方案:https://stackoverflow.com/a/9502074/698168.它使用W3C页面可见性API、模糊/聚焦和鼠标移动的组合。与Alt+Tab相关的隐藏HTML页面是以概率的方式识别的(即,您无法确定您的页面是否100%准确隐藏)。
当在选项卡之间切换和在应用程序之间切换时,我们可以执行以下操作
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);
我遇到了一个非常简单的解决方案。
您只需要在将事件侦听器附加到文档时将false传递给useCapture。工作起来很有魅力!
document.addEventListener('visibilitychange', function () {
// code goes here
}, false)