女王控的博客

Page Visibility(页面可见性) API介绍

API

目前页面可见性API有两个属性,一个事件,如下:

  • document.hidden: Boolean值,表示当前页面可见还是不可见
  • document.visibilityState: 返回当前页面的可见状态

    • hidden
    • visible
    • prerender
    • preview
  • visibilitychange: 当可见状态改变时候触发的事件

兼容

var pageVisibility = (function() {
    var prefixSupport, keyWithPrefix = function(prefix, key) {
        if (prefix !== "") {
            // 首字母大写
            return prefix + key.slice(0,1).toUpperCase() + key.slice(1);    
        }
        return key;
    };
    var isPageVisibilitySupport = (function() {
        var support = false;
        if (typeof window.screenX === "number") {
            ["webkit", "moz", "ms", "o", ""].forEach(function(prefix) {
                if (support == false && document[keyWithPrefix(prefix, "hidden")] != undefined) {
                    prefixSupport = prefix;
                    support = true;
                }
            });
        }
        return support;
    })();
    
    var isHidden = function() {
        if (isPageVisibilitySupport) {
            return document[keyWithPrefix(prefixSupport, "hidden")];
        }
        return undefined;
    };
    
    var visibilityState = function() {
        if (isPageVisibilitySupport) {
            return document[keyWithPrefix(prefixSupport, "visibilityState")];
        }
        return undefined;
    };
    
    return {
        hidden: isHidden(),
        visibilityState: visibilityState(),
        visibilitychange: function(fn, usecapture) {
            usecapture = undefined || false;
            if (isPageVisibilitySupport && typeof fn === "function") {
                return document.addEventListener(prefixSupport + "visibilitychange", function(evt) {
                    this.hidden = isHidden();
                    this.visibilityState = visibilityState();
                    fn.call(this, evt);
                }.bind(this), usecapture);
            }
            return undefined;
        }
    };    
})(undefined);

原生属性事件对应关系如下:

pageVisibility.hidden === document.hidden(兼容处理)
pageVisibility.visibilityState=== document.visibilityState(兼容处理)
pageVisibility.visibilitychange(function() { /* this指的就是pageVisibility */ }); === document.addEventListener("visibilitychange", function() {});(兼容处理)

应用

视频播放

进入页面播放,离开页面暂停。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    html,
    body {
      background-color: white;
      margin: 0;
    }

  </style>
</head>
<body>
  <div class="show">
    <div class="demo">
      <video id="videoElement" src="./cat2.mp4" width="320" height="240" controls="" autoplay=""></video>
    </div>
  </div>
  <script>
    var pageVisibility = (function() {
        var prefixSupport, keyWithPrefix = function(prefix, key) {
            if (prefix !== "") {
                // 首字母大写
                return prefix + key.slice(0,1).toUpperCase() + key.slice(1);
            }
            return key;
        };
        var isPageVisibilitySupport = (function() {
            var support = false;
            if (typeof window.screenX === "number") {
                ["webkit", "moz", "ms", "o", ""].forEach(function(prefix) {
                    if (support == false && document[keyWithPrefix(prefix, "hidden")] != undefined) {
                        prefixSupport = prefix;
                        support = true;
                    }
                });
            }
            return support;
        })();

        var isHidden = function() {
            if (isPageVisibilitySupport) {
                return document[keyWithPrefix(prefixSupport, "hidden")];
            }
            return undefined;
        };

        var visibilityState = function() {
            if (isPageVisibilitySupport) {
                return document[keyWithPrefix(prefixSupport, "visibilityState")];
            }
            return undefined;
        };

        return {
            hidden: isHidden(),
            visibilityState: visibilityState(),
            visibilitychange: function(fn, usecapture) {
                usecapture = undefined || false;
                if (isPageVisibilitySupport && typeof fn === "function") {
                    return document.addEventListener(prefixSupport + "visibilitychange", function(evt) {
                        this.hidden = isHidden();
                        this.visibilityState = visibilityState();
                        fn.call(this, evt);
                    }.bind(this), usecapture);
                }
                return undefined;
            }
        };
    })(undefined);
  </script>
  <script>
    // 以上为方法,以下为测试执行脚本
    (function() {
      if (typeof pageVisibility.hidden !== "undefined") {
        var eleVideo = document.querySelector("#videoElement");
        // 视频时间更新的时候
        eleVideo.addEventListener("timeupdate", function() {
          document.title = "第" + Math.floor(videoElement.currentTime) + "秒";
        }, false);
        // 视频暂停的时候
        eleVideo.addEventListener("pause", function(){
          if (pageVisibility.hidden) {
            // 如果是因为页面不可见导致的视频暂停
            sessionStorage.pauseByVisibility = "true";
          }
        }, false);
        // 视频播放时候
        eleVideo.addEventListener("play", function() {
          sessionStorage.pauseByVisibility = "false";
        }, false);
        // 本页面可见性改变的时候
        pageVisibility.visibilitychange(function() {
          if (this.hidden) {
            // 页面不可见
            eleVideo.pause();
          } else if (sessionStorage.pauseByVisibility === "true") {
            // 页面可见
            eleVideo.play();
          }
        });
      } else {
        alert("弹框???没错,因为你的这个浏览器不支持Page Visibility API的啦!");
      }
    })();
  </script>
</body>
</html>

登录同步

  1. 去淘宝买东西,未登录状态下,进入首页。
  2. 然后新窗口打开任意页面,登录并成功返回。
  3. 再次访问刚才打开的首页,发现页面还是未登录状态(见下图),实际上用户已经登录了。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    html,
    body {
      background-color: white;
      margin: 0;
    }


  </style>
</head>
<body>
  <div class="show">
    <div class="demo">
      <p id="loginInfo">
      </p>
    </div>
  </div>
  <script>
    var pageVisibility = (function() {
        var prefixSupport, keyWithPrefix = function(prefix, key) {
            if (prefix !== "") {
                // 首字母大写
                return prefix + key.slice(0,1).toUpperCase() + key.slice(1);
            }
            return key;
        };
        var isPageVisibilitySupport = (function() {
            var support = false;
            if (typeof window.screenX === "number") {
                ["webkit", "moz", "ms", "o", ""].forEach(function(prefix) {
                    if (support == false && document[keyWithPrefix(prefix, "hidden")] != undefined) {
                        prefixSupport = prefix;
                        support = true;
                    }
                });
            }
            return support;
        })();

        var isHidden = function() {
            if (isPageVisibilitySupport) {
                return document[keyWithPrefix(prefixSupport, "hidden")];
            }
            return undefined;
        };

        var visibilityState = function() {
            if (isPageVisibilitySupport) {
                return document[keyWithPrefix(prefixSupport, "visibilityState")];
            }
            return undefined;
        };

        return {
            hidden: isHidden(),
            visibilityState: visibilityState(),
            visibilitychange: function(fn, usecapture) {
                usecapture = undefined || false;
                if (isPageVisibilitySupport && typeof fn === "function") {
                    return document.addEventListener(prefixSupport + "visibilitychange", function(evt) {
                        this.hidden = isHidden();
                        this.visibilityState = visibilityState();
                        fn.call(this, evt);
                    }.bind(this), usecapture);
                }
                return undefined;
            }
        };
    })(undefined);
  </script>
  <script>
    // 以上为方法,以下为测试执行脚本
    (function() {
      if (typeof pageVisibility.hidden !== "undefined") {
        var eleLoginInfo = document.querySelector("#loginInfo");
        var funLoginInfo = function() {
          var username = localStorage.username || sessionStorage.username;
          if (username) {
            eleLoginInfo.innerHTML = '欢迎回来,<strong>' + username + '</strong>';
            sessionStorage.username = username;
          } else {
            eleLoginInfo.innerHTML = '您尚未登录,请<a target="_blank" href="'+ location.href.replace("-1.", "-2.") +'">登录</a>';
          }
        }
        pageVisibility.visibilitychange(function() {
          if (!this.hidden) funLoginInfo();
        });

        funLoginInfo();

        // 页面关闭清除localStorage
        window.addEventListener("unload", function() {
          localStorage.removeItem("username");
        })
      } else {
        alert("弹框???没错,因为你的这个浏览器不支持Page Visibility API的啦!");
      }
    })();
  </script>
</body>
</html>

只要该页面不被关闭,你怎样刷新,都是“欢迎回来,某某某”。不过,在实际应用中,检测到已经登录成功,直接刷新当前页面的居多!IE10下,貌似本地存储无法同源不同页面共享,这使得通过HTML5本地存储共享信息的做法遇到了些许阻碍。

精确的在线时长

这个不用多说,只有用户当前这个页面可见的时候,才计算在线时间,这样可以避免挂机的情况,时长计算更准确(这个可能不是个好idea)。

在线聊天离开状态

网页聊天的时候,可以知道用户是否“离开”还是“离线”还是“下线”。当前页面不可见,但连接还在的时候,我们可以确定该人是离开的(涉及隐私,可能也不是个好idea)。

评论

阅读下一篇

浏览器样式小数的处理
2020-01-03 17:59:21
0%