使用 PageVisibility API
作为 Web 开发人员,我们往往对新技术感到兴奋,这些新技术使我们能够创建更具吸引力的交互式 Web 页面。使用 WebGL 的 3D 图形?绝对地。WebAudio 的高级音频功能?肯定的事。使用网络摄像头和麦克风的实时协作应用程序?给我报名!
不那么令人兴奋但同样重要的是允许我们构建运行更高效的应用程序并提供更好的整体用户体验的技术。这就是像 PageVisibility 这样的 API 的用武之地。
Page Visibility API 执行一个简单但重要的功能——它让您的应用程序知道页面何时对用户可见。这条基本信息允许创建在不被查看时行为不同的网页。考虑几个例子:
- 从服务器检索信息的网页在不被主动查看时会减慢其更新周期
- 显示旋转图像轮播或视频/音频内容的页面可以暂停,直到用户再次显示该页面
- 应用程序可以决定仅在隐藏时才向用户显示通知
起初,这个 API 可能看起来除了用户方便之外没有多大用处,但考虑到移动 Web 浏览的巨大增长,任何有助于节省设备电池电量的东西都变得非常重要。通过使用 PageVisibility API,您的网站可以帮助用户的设备消耗更少的电量并延长使用寿命。
在撰写本文时,API 规范处于候选推荐阶段,它提供了用于检测文档可见性状态的属性以及用于响应可见性变化的事件。
在本教程中,我将介绍 API 的基础知识,并展示如何将其应用到一些实际示例中(如果您是不耐烦的类型,请随意 跳过它们)。
文档可见性属性
当前 版本的 PageVisibilityAPI 规范 定义了两个文档属性: booleanhidden
和 enumeration visibilityState
。visibilityState 属性目前有四个可能的值:hidden、visible、prerender 和 unloaded。
注意:这些属性仅在 Android 浏览器中以供应商为前缀,您需要使用前缀版本,例如 webkitHidden 和 webkitVisibilityState。所有其他支持的浏览器(IE 10+、Firefox、Chrome、Safari)都实现了无前缀版本。
如您所料,当文档完全不可见时, hidden 属性返回 true。通常,这意味着文档被最小化、在背景选项卡上、操作系统的锁定屏幕已打开等。如果文档的任何部分在至少一个显示器上至少部分可见,则该属性设置为 false。此外,为了适应辅助工具,当诸如屏幕放大镜之类的工具完全遮住了文档但正在显示它的视图时,可以将 hidden 属性设置为 false。
处理供应商前缀
为了将注意力集中在代码上而不是所有特定于供应商的前缀上,我将使用一些帮助函数来隔离浏览器特定的内容。一旦您放弃对 Android 4.4 浏览器的支持,您就可以删除这部分并坚持使用标准名称。
function getHiddenProp(){
var prefixes = ['webkit','moz','ms','o'];
// if 'hidden' is natively supported just return it
if ('hidden' in document) return 'hidden';
// otherwise loop over all the known prefixes until we find one
for (var i = 0; i < prefixes.length; i++){
if ((prefixes[i] + 'Hidden') in document)
return prefixes[i] + 'Hidden';
}
// otherwise it's not supported
return null;
}
文档属性示例
现在我们可以编写一个跨浏览器函数 ,isHidden()
来查看文档是否可见。
function isHidden() {
var prop = getHiddenProp();
if (!prop) return false;
return document[prop];
}
要更详细地查看文档的可见性,您可以使用 visibilityState 属性。此属性返回以下四个值之一:
"hidden"
:文档完全隐藏在视图之外"visible"
:文档在至少一个显示设备上至少部分可见"prerender"
:文档在屏幕外加载且不可见(此值是可选的;并非所有浏览器都必须支持它)"unloaded"
:如果要卸载文档,则返回此值(此值是可选的;并非所有浏览器都一定支持它)
VisibilityChange 事件
除了可见性属性之外,还有一个可见性更改事件,该事件会在文档的可见性状态更改时触发。您可以直接在文档对象上为此事件注册一个事件侦听器:
事件示例
// use the property name to generate the prefixed event name
var visProp = getHiddenProp();
if (visProp) {
var evtname = visProp.replace(/[H|h]idden/,'') + 'visibilitychange';
document.addEventListener(evtname, visChange);
}
function visChange() {
var txtFld = document.getElementById('visChangeText');
if (txtFld) {
if (isHidden())
txtFld.value += "Tab Hidden!\n";
else
txtFld.value += "Tab Visible!\n";
}
}
您可以在下面的文本编辑字段中看到上述代码示例的效果。尝试隐藏和显示包含此页面的选项卡并观察编辑字段的内容变化,如果您看到文本“PageVisibilityAPI not supported!” 那么你的浏览器不支持API。
实际例子
播放和暂停视频
此示例说明如何使用 PageVisibility API 暂停和播放视频。开始播放视频,然后在浏览器中的选项卡之间切换,并注意视频如何(在支持的浏览器中)随着选项卡的可见性变化而暂停和播放。
这是通过监听 visibilityChange 事件然后切换视频的状态来完成的:
window.addEventListener("load", function vidDemo() {
sessionStorage.initialPlay = false;
var vidElem = document.getElementById("video-demo");
var visProp = getHiddenProp();
if (visProp) {
vidElem.addEventListener("play", function() {
sessionStorage.initialPlay = true;
});
var evtName = visProp.replace(/[H|h]idden/,'') + 'visibilitychange';
document.addEventListener(evtName, startStopVideo);
}
function startStopVideo() {
if (document[visProp]) {
vidElem.pause();
}
else if (vidElem.paused && sessionStorage.initialPlay == "true") {
vidElem.play();
}
}
});
仅在隐藏选项卡时显示通知
W3C 通知 API允许您向用户显示弹出通知窗口以引起他们的注意。但是,当用户已经在关注页面时,这可能会很烦人。使用 PageVisibility API,您可以选择仅在选项卡隐藏时显示这些通知。
通过单击“启用通知”按钮启用通知。然后点击“通知我!” 按钮,然后从选项卡中切换。5 秒后,代码将检查选项卡是否隐藏并显示通知。否则,将使用标准警报。
这是代码:
window.addEventListener("load", function notifyDemo() {
var propName = "";
var oNotify=null;
var visProp = getHiddenProp();
document.getElementById("notify-demo").addEventListener("click", function() {
oNotify = null;
if (window.webkitNotifications) {
setTimeout(showNotification, 5000);
if (window.webkitNotifications.checkPermission() == 0) { // 0 is PERMISSION_ALLOWED
oNotify = window.webkitNotifications.createNotification('', 'Notification', 'You have been notified!');
}
}
});
document.getElementById("notify-enable").addEventListener("click", function() {
window.webkitNotifications.requestPermission();
});
function showNotification() {
if (document[visProp] && window.webkitNotifications && oNotify) {
oNotify.show();
}
else {
alert("You have been notified!");
}
}
});
如果页面正在预呈现,则推迟 Google Analytics
某些浏览器,例如 Google Chrome,具有预渲染页面的能力(您可以在此处阅读有关 Chrome 预渲染的更多信息)。此过程涉及下载呈现页面所需的所有资源 - 包括页面包含的任何脚本。许多第三方网站使用 Google Analytics 来检测他们的页面何时被查看,但如果页面是预先呈现但用户从未实际查看过的,则此计数可能会出现偏差。
为防止出现此问题,您可以使用 PageVisibility API 来检测您的页面是否正在预渲染,如果是这种情况,则跳过跟踪视图。通常,您的页面将包含如下所示的代码:
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXX-X']);
_gaq.push(['_trackPageview']);
在这种情况下,总是会记录 _trackPageview 事件,即使页面没有显示给用户。检测预渲染的脚本如下所示:
var bHavePV = getHiddenProp();
var bInitialShow = false;
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXX-X']);
if (bHavePV) {
document.addEventListener("visibilityChange", handleVisEvt);
}
else {
_gaq.push(['_trackPageview']); // track page view normally when PageVisibility is not present
}
function handleVisEvt() {
if (document.visibilityState == "prerender") {
_trackEvent("pagedata", "prerender"); // might be interesting to keep track of pre-rendering
}
if (document.visibilityState == "visible" && !bInitialShow) {
bInitialShow = true; // don't trigger this code again
_gaq.push(['_trackPageview']);
}
}
概括
构建一个出色的 Web 应用程序所涉及的不仅仅是使用用户可以看到并与之交互的引人注目的、引人注目的功能。一个真正出色的应用程序会体贴地利用用户的资源和注意力,而 Page Visibility API 是该难题的重要组成部分。要了解有关构建注重资源的 Web 应用程序的更多信息,请查看我们其他与性能相关的文章。
外部参考
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
![扫码二维码加入Web技术交流群](/public/img/jiaqun_03.jpg)
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论