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

这个API本身非常简单,由以下三部分组成

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

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。为了在两个浏览器中都能侦听到该事件,可以像下面的例子一样,为每个事件都指定相同的事件处理程序:

var EventUtil = {
    addHandler: function(element, type, handler) {
        if(element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if(element.attachEvent) {
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    }
};

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, "visibilitychange", handleVisibilityChange);
EventUtil.addHandler(document, "msvisibilitychange", handleVisibilityChange);
EventUtil.addHandler(document, "webkitvisibilitychange", handleVisibilityChange);

以上代码同时适用与IE与Chrome。而且,API的这一部分已经相对稳定,因此在实际的Web开发中也可以使用以上代码。

关于这一API的实现,差异最大的是document.visibilityState属性。IE10 PR2的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属性。