• 浏览器页面可见性事件详解及基本应用


    页面可见性改变事件 visibilitychange

    详解


    Page Visibility API 标准概述

    这是一个页面可见性API,浏览器标签页被隐藏或显示的时候会触发 visibilitychange事件。

    这是 HTML5 新提供的一个 api ,作用是记录当前标签页在浏览器中的激活状态。
    所谓“激活状态”指当前标签是否正在被用户浏览。

    我们知道,平时在 PC 端浏览网页的时候,使用的都是选项卡这种方式浏览网页,使用这种方式浏览,任何给定网页都有可能在后台,因此对用户不可见。页面可见性 API 提供了开发者可以观察的事件,以便了解文档何时可见或隐藏,以及查看页面当前可见性状态的功能。

    页面可见性 API 对于节省资源和提到性能特别有用,它使页面在文档不可见时避免执行不必要的任务。

    当用户最小化窗口或切换到另一个选项卡时,API会发送 visibilitychange 事件,让开发者知道页面状态已更改。你可以检测事件并执行某些操作或行为。例如,如果你的网络应用正在播放视频,则可以在用户将标签放入背景时暂停视频,并在用户返回标签时恢复播放。 用户不会在视频中丢失位置,视频的音轨不会干扰新前景选项卡中的音频,并且用户在此期间不会错过任何视频。这种体验是用户无感知的,并且对于用户体验是非常友好的。

    规范的使用这个API可以减少对用户宽带的占用,减少服务器压力,节省用户内存,以及到达更好的播放效果。


    使用场景

    • 网站有图片轮播效果,只有在用户观看轮播的时候,才会自动展示下一张幻灯片。
    • 显示信息仪表盘的应用程序不希望在页面不可见时轮询服务器进行更新。
    • 页面想要检测是否正在渲染,以便可以准确的计算网页浏览量(埋点使用场景)。
    • 当设备进入待机模式时,网站想要关闭设备声音(用户按下电源键关闭屏幕)。

    该API的属性和事件

    HTML5 中专门为 document 元素添加了相关属性和事件:


    属性

      1. Document.hidden 只读属性 布尔值 简单的表示标签页显示或者隐藏
        如果页面处于被认为是对用户隐藏状态时返回 true ,否则返回 false
      1. Document.visibilityState 只读属性
        是一个用来展示文档可见性状态的字符串,可能的值:
      • visible : 页面内容至少是部分可见。 在实际中,这意味着页面是非最小化窗口的前景选项卡。
      • hidden : 页面内容对用户不可见。 在实际中,这意味着文档可以是一个后台标签,或是最小化窗口的一部分,或是在操作系统锁屏激活的状态下。
      • prerender : 页面内容正在被预渲染且对用户是不可见的(被 document.hidden 当做隐藏). 文档可能初始状态为 prerender,但绝不会从其它值转为该值。 注释:浏览器支持是可选的。
      • unloaded : 页面正在从内存中卸载。 注释:浏览器支持是可选的。
      1. Document.onvisibilitychange
      • EventListener 提供在visibilitychange 事件被触发时要调用的代码。

    基本应用


    监听该页面可视状态

    function onVisibilityChange() {
      if (!document[this.hiddenProperty]) {
        console.log('页面显示');
      } else {
        console.log('页面隐藏');
      }
    }
    
    function addVisibilityListener() {
      var hiddenProperty = 'hidden' in document ? 'hidden' : 'webkitHidden' in document ? 'webkitHidden' : 'mozHidden' in document ? 'mozHidden' : null;
      var visibilityChangeEvent = hiddenProperty.replace(/hidden/i, 'visibilitychange');
      document.addEventListener(visibilityChangeEvent, onVisibilityChange, false);
    }
    
    function removeVisilityListener() {
      var hiddenProperty = 'hidden' in document ? 'hidden' : 'webkitHidden' in document ? 'webkitHidden' : 'mozHidden' in document ? 'mozHidden' : null;
      var visibilityChangeEvent = hiddenProperty.replace(/hidden/i, 'visibilitychange');
      document.removeEventListener(visibilityChangeEvent, onVisibilityChange, false);
    }
    

    控制视频暂停⏸播放▶示例

    // Set the name of the hidden property and the change event for visibility
    var hidden, visibilityChange;
    if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support
      hidden = "hidden";
      visibilityChange = "visibilitychange";
    } else if (typeof document.msHidden !== "undefined") {
      hidden = "msHidden";
      visibilityChange = "msvisibilitychange";
    } else if (typeof document.webkitHidden !== "undefined") {
      hidden = "webkitHidden";
      visibilityChange = "webkitvisibilitychange";
    }
    
    var videoElement = document.getElementById("videoElement");
    
    // If the page is hidden, pause the video;
    // if the page is shown, play the video
    function handleVisibilityChange() {
      if (document[hidden]) {
        videoElement.pause();
      } else {
        videoElement.play();
      }
    }
    
    // Warn if the browser doesn't support addEventListener or the Page Visibility API
    if (typeof document.addEventListener === "undefined" || hidden === undefined) {
      console.log("This demo requires a browser, such as Google Chrome or Firefox, that supports the Page Visibility API.");
    } else {
      // Handle page visibility change
      document.addEventListener(visibilityChange, handleVisibilityChange, false);
    
      // When the video pauses, set the title.
      // This shows the paused
      videoElement.addEventListener("pause", function(){
        document.title = 'Paused';
      }, false);
    
      // When the video plays, set the title.
      videoElement.addEventListener("play", function(){
        document.title = 'Playing';
      }, false);
    }
    

    应用实例场景:带有声音的视频

    在此例中,当你切换到另一个标签时视频会暂停,当你返回到当前标签时视频会再次播放,代码如下:

    <main>
      <video id="videoElement" controls="" poster="thumbnail.jpg">
        <source src="https://s3-ap-northeast-1.amazonaws.com/daniemon/demos/The%2BVillage-Mobile.mp4" type="video/mp4" media="all and (max-680px)">
        <source src="https://s3-ap-northeast-1.amazonaws.com/daniemon/demos/The%2BVillage-Mobile.webm" type="video/webm" media="all and (max-680px)">
        <source src="https://s3-ap-northeast-1.amazonaws.com/daniemon/demos/The%2BVillage-SD.mp4" type="video/mp4">
        <source src="https://s3-ap-northeast-1.amazonaws.com/daniemon/demos/The%2BVillage-SD.webm" type="video/webm">
        <p>Sorry, there's a problem playing this video. Please try using a different browser.</p>
      </video>
    </main>
    
      // 设置隐藏属性和改变可见属性的事件的名称
      var hidden, visibilityChange;
      if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support
        hidden = "hidden";
        visibilityChange = "visibilitychange";
      } else if (typeof document.msHidden !== "undefined") {
        hidden = "msHidden";
        visibilityChange = "msvisibilitychange";
      } else if (typeof document.webkitHidden !== "undefined") {
        hidden = "webkitHidden";
        visibilityChange = "webkitvisibilitychange";
      }
    
      var videoElement = document.getElementById("videoElement");
    
      // 如果页面是隐藏状态,则暂停视频;如果页面是展示状态,则播放视频
      function handleVisibilityChange() {
        if (document[hidden]) {
          videoElement.pause();
        } else {
          videoElement.play();
        }
      }
    
      // 如果浏览器不支持addEventListener 或 Page Visibility API 给出警告
      if (typeof document.addEventListener === "undefined" || typeof document[hidden] === "undefined") {
        console.log("This demo requires a browser, such as Google Chrome or Firefox, that supports the Page Visibility API.");
      } else {
    
      // 处理页面可见属性的改变
      document.addEventListener(visibilityChange, handleVisibilityChange, false);
    
      // 当视频暂停,设置title
      // This shows the paused
      videoElement.addEventListener("pause", function(){
        document.title = 'Paused';
      }, false);
    
      // 当视频播放,设置title
      videoElement.addEventListener("play", function(){
        document.title = 'Playing'; 
      }, false);
    }
    

    兼容性处理

    为了支持老版本的浏览器,我们需要对document.hidden在做一些前缀处理:

    function getHiddenProp(){
      var prefixes = ['webkit','moz','ms','o'];
      // 如果hidden 属性是原生支持的,我们就直接返回
      if ('hidden' in document) {
        return 'hidden';
      }
      // 其他的情况就循环现有的浏览器前缀,拼接我们所需要的属性 
      for (var i = 0; i < prefixes.length; i++){
        // 如果当前的拼接的前缀在 document对象中存在 返回即可
        if ((prefixes[i] + 'Hidden') in document) {
          return prefixes[i] + 'Hidden';
        }  
      }
      // 其他的情况 直接返回null
      return null;
    }
    

    同样的,我们可以获取 document.visibilityState 属性:

    function getVisibilityState() {
      var prefixes = ['webkit', 'moz', 'ms', 'o'];
      if ('visibilityState' in document) {
        return 'visibilityState';
      }
      for (var i = 0; i < prefixes.length; i++) {
        if ((prefixes[i] + 'VisibilityState') in document){
          return prefixes[i] + 'VisibilityState';
        }  
      }
      // 找不到返回 null
      return null;
    }
    

    visibilitychange监听事件

    你可以在 document 对象上注册一个监听 visibilitychange 事件,根据 document.hidden 或者 document.visibilityState 属性做一些业务逻辑:

    var visProp = getHiddenProp();
    if (visProp) {
      // 有些浏览器也需要对这个事件加前缀以便识别。
      var evtname = visProp.replace(/[H|h]idden/, '') + 'visibilitychange';
      document.addEventListener(evtname, function () {
        document.title = document[getVisibilityState()]+"状态";
      },false);
    }
    

    上面的代码会在页面可见性发生变化时修改 document.title 的值

    文章地址:https://www.cnblogs.com/dragonir/p/14417106.html 作者:dragonir

  • 相关阅读:
    使用JFileChooser实现在指定文件夹下批量添加根据“数字型样式”或“非数字型样式”命令的文件夹
    51Nod 1376 最长递增子序列的数量 (DP+BIT)
    POJ 2728 Desert King (最优比率树)
    UVa 11280 Flying to Fredericton (DP + Dijkstra)
    UVa 11367 Full Tank? (DP + Dijkstra)
    UVa 10269 Adventure of Super Mario (Floyd + DP + BFS)
    UVaLive 4452 The Ministers' Major Mess (TwoSat)
    UVa 11294 Wedding (TwoSat)
    HDU 3247 Resource Archiver (AC自动机+BFS+状压DP)
    HDU 5957 Query on a graph (拓扑 + bfs序 + 树剖 + 线段树)
  • 原文地址:https://www.cnblogs.com/dragonir/p/14417106.html
Copyright © 2020-2023  润新知