javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > h5后台切换检测visibilitychange

h5后台切换检测利用visibilitychange的缺点超详细分析

作者:拉不动的猪

在移动端的H5应用场景中,用户经常会将页面切到后台再切回前台,浏览器对后台页面的资源调度、定时任务执行和网络请求策略会产生显著变化,这篇文章主要介绍了h5后台切换检测利用visibilitychange的缺点分析的相关资料,需要的朋友可以参考下

一、什么是visibilitychange事件?

visibilitychange 是浏览器提供的原生事件,属于 Page Visibility API(页面可见性 API)的核心部分。当页面的可见性状态发生变化时(如页面从 “显示” 变为 “隐藏”,或从 “隐藏” 变为 “显示”),浏览器会触发该事件,当然如果是uniapp或者是wx也会提供类似apphide appshow这些API。

二、核心属性与事件

1.document.hidden(状态判断核心)

2.document.visibilityState(更详细的状态描述)

3.visibilitychange事件

三、基本用法(完整代码示例)

1. 基础监听逻辑

// 监听 visibilitychange 事件
document.addEventListener('visibilitychange', handleVisibilityChange);

// 事件处理函数
function handleVisibilityChange() {
  // 方法1:用 document.hidden 判断
  if (document.hidden) {
    console.log('页面进入后台(不可见)');
    // 执行后台逻辑:暂停视频、清除定时器、保存数据等
    pauseVideo();
    clearInterval(timer);
    saveUserState();
  } else {
    console.log('页面回到前台(可见)');
    // 执行前台逻辑:恢复视频播放、重启定时器、刷新数据等
    playVideo();
    restartTimer();
    refreshData();
  }

  // 方法2:用 document.visibilityState 判断(更细致)
  switch (document.visibilityState) {
    case 'visible':
      console.log('页面可见(前台)');
      break;
    case 'hidden':
      console.log('页面隐藏(后台)');
      break;
    case 'prerender':
      console.log('页面预渲染中');
      break;
    case 'unloaded':
      console.log('页面即将卸载');
      break;
  }
}

2. 解除监听(避免内存泄漏)

当页面不需要监听状态变化时(如组件销毁),需移除事件监听:

// 页面卸载前解除监听
window.addEventListener('beforeunload', function() {
  document.removeEventListener('visibilitychange', handleVisibilityChange);
});

// 或在 Vue/React 组件销毁时(以 Vue 为例)
export default {
  beforeDestroy() {
    document.removeEventListener('visibilitychange', this.handleVisibilityChange);
  }
};

四、适用场景

1. 媒体播放控制

2. 减少无效请求

3. 记录用户在线状态

4. 防止表单数据丢失

五、兼容性与浏览器支持

1. 主流浏览器支持情况

六、注意

1. 与pagehide/pageshow的区别

2. 微信 / 企业微信环境的特殊性

3. 避免过度使用

4. 锁屏状态的触发

visibilitychange 事件是 H5 页面监听 “前台 / 后台切换” 的最优方案,具有以下优势:

缺点:无法区分隐藏原因

是的,你没看错,先前讲到的只是常规情况下用户手动切换后台的触发, 但是在一些场景下还是要慎用

1. 无法区分 “切后台” 的具体原因

visibilitychange 只能判断页面 “可见” 或 “隐藏”,但无法区分隐藏的具体场景,例如:

2. 部分浏览器 / 场景下触发时机不精准

3. 无法监听 “页面关闭” 的最终状态

visibilitychange 的 unloaded 状态在多数浏览器中支持不佳,且页面真正关闭时(如用户点击关闭标签页),visibilitychange 可能与 beforeunloadpagehide 事件顺序混乱,难以可靠判断 “用户是否彻底离开”。例如,用户关闭标签页时,hidden 会先变为 true,但此时页面即将卸载,后续逻辑(如上报数据)可能因页面关闭而中断。

4. 对 “部分可见” 状态的判断有限

document.visibilityState = 'visible' 表示页面 “至少部分可见”(如浏览器窗口只露出一小块),但无法判断页面是否 “完全可见”(如被其他窗口遮挡了大部分)。如果业务需要精确判断 “用户是否正在全屏浏览”,visibilitychange 无法满足,需结合 document.fullscreenElement 等 API 辅助判断。

用户是 “切换到其他 App” 还是 “切换到浏览器的其他标签页”?

是 “手机锁屏” 还是 “浏览器窗口最小化”

是 “分享到微信好友后暂时离开” 还是 “彻底关闭页面”?

上面三种是常见的场景,通常可以这样的辅助方法进行判断

一、区分 “切换到其他 App” vs “切换到浏览器其他标签页”

核心思路:利用浏览器标签页的 “焦点状态” 和 “页面可见性” 的关联性

辅助判断方法:

  1. 结合 focus/blur 事件与定时器延迟检测(一般情况可用,所以慎用)

    let isTabSwitch = false;
    let timer;
    
    // 监听可见性变化
    document.addEventListener('visibilitychange', () => {
      if (document.hidden) {
        // 页面隐藏时启动定时器,检测延迟
        timer = setTimeout(() => {
          // 若定时器延迟超过100ms,大概率是切换到其他App(浏览器被冻结)
          console.log('可能切换到其他App');
        }, 100);
      } else {
        clearTimeout(timer);
        // 页面恢复时,若之前触发了blur且无明显延迟,可能是切换标签页
        if (isTabSwitch) {
          console.log('可能切换到浏览器其他标签页');
          isTabSwitch = false;
        }
      }
    });
    
    // 监听焦点变化
    window.addEventListener('blur', () => {
      if (document.hidden) {
        isTabSwitch = true; // 隐藏时失去焦点,可能是切换标签页
      }
    });
    
    • 原理:切换标签页时,浏览器仍在前台运行,定时器延迟较小;切换到其他 App 时,浏览器进入后台,定时器可能被延迟执行。

二、区分 “手机锁屏” vs “浏览器窗口最小化”

核心思路:利用 “锁屏” 的特殊性 —— 通常伴随设备屏幕关闭,而 “窗口最小化” 仅窗口不可见

辅助判断方法:

  1. 结合 screen 对象的亮度或唤醒状态(移动端有限支持):

    document.addEventListener('visibilitychange', () => {
      if (document.hidden) {
        // 检测屏幕是否变暗(部分设备支持)
        if (typeof screen.brightness !== 'undefined' && screen.brightness < 0.1) {
          console.log('可能是手机锁屏');
        } else {
          console.log('可能是浏览器窗口最小化');
        }
      }
    });
    
    • 注意:screen.brightness 兼容性较差(主要支持安卓部分浏览器),iOS 基本不支持。
  2. 监听 touchstart 事件是否失效(移动端):锁屏后,页面无法接收触摸事件,可在页面恢复可见时检测是否有 “锁屏期间的触摸记录”(无记录则可能是锁屏):

    let hasTouchDuringHidden = false;
    document.addEventListener('touchstart', () => {
      if (document.hidden) {
        hasTouchDuringHidden = true;
      }
    });
    
    document.addEventListener('visibilitychange', () => {
      if (!document.hidden) {
        if (!hasTouchDuringHidden) {
          console.log('可能是手机锁屏(期间无触摸)');
        } else {
          console.log('可能是窗口最小化(期间可能有触摸其他窗口)');
          hasTouchDuringHidden = false;
        }
      }
    });
    

三、区分 “分享到微信好友后暂时离开” vs “彻底关闭页面”

核心思路:利用 “分享” 操作的前置行为(如点击分享按钮)和页面生命周期差异

辅助判断方法:

  1. 监听微信分享按钮的点击事件(微信 H5 场景):在微信环境中,用户分享前通常会点击自定义的 “分享按钮”,可通过该行为标记 “可能是分享导致的离开”:

    let isSharing = false;
    // 假设分享按钮id为shareBtn
    document.getElementById('shareBtn').addEventListener('click', () => {
      isSharing = true; // 标记用户触发了分享操作
    });
    
    document.addEventListener('visibilitychange', () => {
      if (document.hidden) {
        if (isSharing) {
          console.log('可能是分享到微信好友后暂时离开');
          // 30秒后若未恢复可见,视为可能关闭页面
          setTimeout(() => {
            if (document.hidden) {
              console.log('分享后未返回,可能已关闭页面');
              isSharing = false;
            }
          }, 30000);
        } else {
          console.log('可能是其他原因关闭页面');
        }
      } else {
        if (isSharing) {
          console.log('分享后返回页面');
          isSharing = false;
        }
      }
    });
    
  2. 结合 pagehide 事件判断页面是否卸载:彻底关闭页面时,pagehide 事件会在 visibilitychange 之后触发,可通过该事件确认 “页面已关闭”:

    let isPageClosed = false;
    window.addEventListener('pagehide', () => {
      isPageClosed = true;
      console.log('页面已关闭');
    });
    
    document.addEventListener('visibilitychange', () => {
      if (document.hidden && !isPageClosed) {
        console.log('页面隐藏但未关闭(可能是分享后暂时离开)');
      }
    });
    

    总结:

    没有绝对的完美,只有不断地完善,当后台切换时还是要尽可能的与原有应用进行事件关联才会更准确的判断用户的操作行为。

到此这篇关于h5后台切换检测利用visibilitychange的缺点超详细分析的文章就介绍到这了,更多相关h5后台切换检测visibilitychange内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文