在我们开发的任何类型的 javascript 应用程序中,都可能存在
功能或应用程序中的任何更改根据
当前用户可见性状态,这可能是暂停正在播放的视频
当用户 ALT+TAB 到不同的窗口时,跟踪有关如何的统计信息
用户与我们的应用程序交互,他多久切换一次
一个不同的标签,他需要多长时间才能返回以及很多
可以从这种 API 中受益的性能改进。
Page Visibility API 为我们提供了两个顶级属性:
document.hidden (boolean) 和 document.visibilityState (可能是
这些字符串中的任何一个:“hidden”、“visible”、“prerender”、“unloaded”)。
如果没有我们可以收听的事件,这还不够好
不过,这就是 API 还提供有用的可见性更改的原因
事件。
所以,这里有一个关于我们如何对可见性采取行动的基本示例
改变:
function handleVisibilityChange() {
if(document.hidden) {
// the page is hidden
} else {
// the page is visible
}
}
document.addEventListener("visibilitychange", handleVisibilityChange, false);
我们还可以检查 document.visibilityState 的值。
处理供应商问题 George Berkeley by 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 规范。这是我们为 document.hidden 得到的定义
属性:
隐藏属性 在获取时,隐藏属性必须返回 true,如果
顶级浏览上下文(根窗口)包含的文档
在浏览器的视口中)[HTML5] 根本不可见。这
如果顶层包含的 Document 属性必须返回 false
浏览上下文在至少一个屏幕上至少部分可见。
如果 Document 的 defaultView 为 null,则在获取时,隐藏的
属性必须返回 true。
为了适应通常是全屏但
仍然显示页面的视图,如果适用,此属性可以
当用户代理没有被最小化而是完全被最小化时返回 false
被其他应用程序遮挡。
我发现事件的实际发生时间有几个不一致的地方
触发,例如(Chrome 41.0.2272.101 m,在 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
并说:
“可见”正在被感知。