女王控的博客

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

API

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

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

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

兼容

js 复制代码
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);

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

js 复制代码
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)。

评论

阅读上一篇

去除冗余 – 精简您的CSS样式代码
2020-01-06 19:50:59

阅读下一篇

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