25.2 Page Visibility API

优质
小牛编辑
117浏览
2023-12-01

不知道用户是不是正在与页面交互,这是困扰广大Web 开发人员的一个主要问题。如果页面最小化了或者隐藏在了其他标签页后面,那么有些功能是可以停下来的,比如轮询服务器或者某些动画效果。而Page Visibility API(页面可见性API)就是为了让开发人员知道页面是否对用户可见而推出的。这个API 本身非常简单,由以下三部分组成。

  • document.hidden:表示页面是否隐藏的布尔值。页面隐藏包括页面在后台标签页中或者浏览器最小化。
  • document.visibilityState:表示下列4 个可能状态的值。
  • 页面在后台标签页中或浏览器最小化。
  • 页面在前台标签页中。
  • 实际的页面已经隐藏,但用户可以看到页面的预览(就像在Windows 7 中,用户把鼠标移动到任务栏的图标上,就可以显示浏览器中当前页面的预览)。
  • 页面在屏幕外执行预渲染处理。
  • visibilitychange 事件:当文档从可见变为不可见或从不可见变为可见时,触发该事件。

在编写本书时,只有IE10 和Chrome 支持Page Visibility API。IE 的版本是在每个属性或事件前面加上ms 前缀,而Chrome 则是加上webkit 前缀。因此document.hidden 在IE 的实现中就是document.msHidden,而在Chrome 的实现中则是document.webkitHidden。检查浏览器是否支持这个API 的最佳方式如下:

function isHiddenSupported() {
return typeof(document.hidden || document.msHidden || document.webkitHidden) != "undefined";
}

类似地,使用同样的模式可以检测页面是否隐藏:

if (document.hidden || document.msHidden || document.webKitHidden){
    //页面隐藏了
} else {
    //页面未隐藏
}

注意,以上代码在不支持该API 的浏览器中会提示页面未隐藏。这是Page Visibility API 有意设计的结果,目的是为了向后兼容。
为了在页面从可见变为不可见或从不可见变为可见时收到通知,可以侦听visibilitychange 事件。在IE 中,这个事件叫msvisibilitychange,而在Chrome 中这个事件叫webkitvisibilitychange。为了在两个浏览器中都能侦听到该事件,可以像下面的例子一样,为每个事件都指定相同的事件处理程序:

function handleVisibilityChange() {
var output = document.getElementById("output"),
msg;
if (document.hidden || document.msHidden || document.webkitHidden) {msg = "Page is now hidden. " + (new Date()) + "<br>";
} else {msg = "Page is now visible. " + (new Date()) + "<br>";
}
output.innerHTML += msg;
}
//要为两个事件都指定事件处理程序
EventUtil.addHandler(document, "msvisibilitychange", handleVisibilityChange);
EventUtil.addHandler(document, "webkitvisibilitychange", handleVisibilityChange);

运行一下
以上代码同时适用于IE 和Chrome。而且,API 的这一部分已经相对稳定,因此在实际的Web 开发中也可以使用以上代码。
关于这一API 的实现,差异最大的是document.visibilityState 属性。IE10 PR 2 的document.msVisibilityState 是一个表示如下4 种状态的数字值。

  • (1) document.MS_PAGE_HIDDEN (0)
  • (2) document.MS_PAGE_VISIBLE (1)
  • (3) document.MS_PAGE_PREVIEW (2)
  • (4) document.MS_PAGE_PRERENDER (3)

在Chrome 中,document.webkitVisibilityState 可能是下列3 个字符串值:

  • (1) "hidden"
  • (2) "visible"
  • (3) "prerender"

Chrome 并没有给每个状态定义对应的常量,但最终的实现很可能会使用常量。由于存在以上差异,所以建议大家先不要完全依赖带前缀的document.visibilityState,最好只使用document.hidden 属性。