最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

h5后臺(tái)切換檢測利用visibilitychange的缺點(diǎn)超詳細(xì)分析

 更新時(shí)間:2026年03月11日 10:47:17   作者:拉不動(dòng)的豬  
在移動(dòng)端的H5應(yīng)用場景中,用戶經(jīng)常會(huì)將頁面切到后臺(tái)再切回前臺(tái),瀏覽器對(duì)后臺(tái)頁面的資源調(diào)度、定時(shí)任務(wù)執(zhí)行和網(wǎng)絡(luò)請求策略會(huì)產(chǎn)生顯著變化,這篇文章主要介紹了h5后臺(tái)切換檢測利用visibilitychange的缺點(diǎn)分析的相關(guān)資料,需要的朋友可以參考下

一、什么是visibilitychange事件?

visibilitychange 是瀏覽器提供的原生事件,屬于 Page Visibility API(頁面可見性 API)的核心部分。當(dāng)頁面的可見性狀態(tài)發(fā)生變化時(shí)(如頁面從 “顯示” 變?yōu)?“隱藏”,或從 “隱藏” 變?yōu)?“顯示”),瀏覽器會(huì)觸發(fā)該事件,當(dāng)然如果是uniapp或者是wx也會(huì)提供類似apphide appshow這些API。

  • 核心作用:判斷頁面是否處于用戶可見狀態(tài)(前臺(tái))或不可見狀態(tài)(后臺(tái),如切換到其他 App、瀏覽器標(biāo)簽頁被切換、手機(jī)鎖屏等)。

二、核心屬性與事件

1.document.hidden(狀態(tài)判斷核心)

  • 布爾值,true 表示頁面當(dāng)前不可見(后臺(tái)),false 表示頁面可見(前臺(tái))。
  • 是判斷頁面狀態(tài)的直接依據(jù)。

2.document.visibilityState(更詳細(xì)的狀態(tài)描述)

  • 字符串類型,返回頁面的具體可見性狀態(tài),有 4 種可能值:

    • visible:頁面可見(至少部分可見,如瀏覽器窗口未最小化,標(biāo)簽頁激活)。
    • hidden:頁面不可見(如切換到其他標(biāo)簽頁、瀏覽器最小化、手機(jī)切后臺(tái))。
    • prerender:頁面正在預(yù)渲染(用戶未實(shí)際看到,通常用于優(yōu)化加載,部分瀏覽器支持)。
    • unloaded:頁面即將被卸載(如關(guān)閉標(biāo)簽頁,部分瀏覽器支持)。
  • 實(shí)際開發(fā)中,hidden 和 visible 是最常用的兩個(gè)狀態(tài)。

3.visibilitychange事件

  • 當(dāng) document.visibilityState 或 document.hidden 變化時(shí)觸發(fā),需通過 document.addEventListener 監(jiān)聽。

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

1. 基礎(chǔ)監(jiān)聽邏輯

// 監(jiān)聽 visibilitychange 事件
document.addEventListener('visibilitychange', handleVisibilityChange);

// 事件處理函數(shù)
function handleVisibilityChange() {
  // 方法1:用 document.hidden 判斷
  if (document.hidden) {
    console.log('頁面進(jìn)入后臺(tái)(不可見)');
    // 執(zhí)行后臺(tái)邏輯:暫停視頻、清除定時(shí)器、保存數(shù)據(jù)等
    pauseVideo();
    clearInterval(timer);
    saveUserState();
  } else {
    console.log('頁面回到前臺(tái)(可見)');
    // 執(zhí)行前臺(tái)邏輯:恢復(fù)視頻播放、重啟定時(shí)器、刷新數(shù)據(jù)等
    playVideo();
    restartTimer();
    refreshData();
  }

  // 方法2:用 document.visibilityState 判斷(更細(xì)致)
  switch (document.visibilityState) {
    case 'visible':
      console.log('頁面可見(前臺(tái))');
      break;
    case 'hidden':
      console.log('頁面隱藏(后臺(tái))');
      break;
    case 'prerender':
      console.log('頁面預(yù)渲染中');
      break;
    case 'unloaded':
      console.log('頁面即將卸載');
      break;
  }
}

2. 解除監(jiān)聽(避免內(nèi)存泄漏)

當(dāng)頁面不需要監(jiān)聽狀態(tài)變化時(shí)(如組件銷毀),需移除事件監(jiān)聽:

// 頁面卸載前解除監(jiān)聽
window.addEventListener('beforeunload', function() {
  document.removeEventListener('visibilitychange', handleVisibilityChange);
});

// 或在 Vue/React 組件銷毀時(shí)(以 Vue 為例)
export default {
  beforeDestroy() {
    document.removeEventListener('visibilitychange', this.handleVisibilityChange);
  }
};

四、適用場景

1. 媒體播放控制

  • 頁面切后臺(tái)時(shí)暫停視頻 / 音頻,切回前臺(tái)時(shí)恢復(fù)播放:

    const video = document.getElementById('myVideo');
    function handleVisibilityChange() {
      if (document.hidden) {
        video.pause(); // 切后臺(tái)暫停
      } else {
        video.play(); // 切前臺(tái)恢復(fù)
      }
    }
    

2. 減少無效請求

  • 頁面在后臺(tái)時(shí),暫停輪詢接口(如實(shí)時(shí)聊天、數(shù)據(jù)刷新),避免浪費(fèi)資源:
    let pollTimer;
    function startPoll() {
      pollTimer = setInterval(() => {
        fetch('/api/refresh'); // 輪詢接口
      }, 5000);
    }
    function stopPoll() {
      clearInterval(pollTimer);
    }
    
    function handleVisibilityChange() {
      if (document.hidden) {
        stopPoll(); // 后臺(tái)停止輪詢
      } else {
        startPoll(); // 前臺(tái)重啟輪詢
      }
    }
    

3. 記錄用戶在線狀態(tài)

  • 切后臺(tái)時(shí)記錄 “離線時(shí)間”,切前臺(tái)時(shí)更新 “在線狀態(tài)”:

    let lastLeaveTime;
    function handleVisibilityChange() {
      if (document.hidden) {
        lastLeaveTime = new Date().getTime(); // 記錄切后臺(tái)時(shí)間
        reportUserState('offline'); // 上報(bào)離線狀態(tài)
      } else {
        const onlineTime = new Date().getTime() - lastLeaveTime;
        console.log(`用戶離線時(shí)長:${onlineTime}ms`);
        reportUserState('online'); // 上報(bào)在線狀態(tài)
      }
    }
    

4. 防止表單數(shù)據(jù)丟失

  • 切后臺(tái)時(shí)自動(dòng)保存表單草稿,避免用戶忘記提交:

    function saveFormDraft() {
      const formData = {
        username: document.getElementById('username').value,
        content: document.getElementById('content').value
      };
      localStorage.setItem('formDraft', JSON.stringify(formData));
    }
    
    function handleVisibilityChange() {
      if (document.hidden) {
        saveFormDraft(); // 切后臺(tái)時(shí)保存草稿
      }
    }
    

五、兼容性與瀏覽器支持

1. 主流瀏覽器支持情況

  • PC 端:Chrome、Firefox、Edge、Safari(≥6.1)全支持。
  • 移動(dòng)端:微信內(nèi)置瀏覽器、手機(jī) Chrome、Safari(iOS ≥7.1)、安卓系統(tǒng)瀏覽器(≥4.4)全支持。
  • 低版本兼容:IE10+ 支持,但需用前綴 msVisibilityChange 和 msHidden(實(shí)際開發(fā)中可忽略,IE 市場占比極低)。

六、注意

1. 與pagehide/pageshow的區(qū)別

  • visibilitychange:僅關(guān)注頁面 “可見性”(是否在前臺(tái)),不關(guān)心頁面是否卸載(如切換標(biāo)簽頁時(shí)觸發(fā),但頁面未關(guān)閉。
  • pagehide:頁面即將被卸載時(shí)觸發(fā)(如關(guān)閉標(biāo)簽頁、跳轉(zhuǎn)頁面),但切后臺(tái)時(shí)也可能觸發(fā),場景更寬泛,判斷精度低于 visibilitychange。
  • 結(jié)論:判斷 “切后臺(tái)” 優(yōu)先用 visibilitychange,判斷 “頁面關(guān)閉” 可用 pagehide。

2. 微信 / 企業(yè)微信環(huán)境的特殊性

  • 微信內(nèi)置瀏覽器完全支持 visibilitychange,無需依賴微信 JS-SDK,可直接使用。
  • 但需注意:微信中 “分享到朋友圈 / 好友” 時(shí),頁面會(huì)短暫切后臺(tái)再切回,可能觸發(fā)一次 visibilitychange(從 visible → hidden → visible),需根據(jù)業(yè)務(wù)判斷是否忽略這種場景。

3. 避免過度使用

  • 頻繁觸發(fā)的邏輯(如大量 DOM 操作)放在 visibilitychange 中可能影響性能,建議僅處理必要操作(如暫停 / 恢復(fù)、保存數(shù)據(jù))。

4. 鎖屏狀態(tài)的觸發(fā)

  • 手機(jī)鎖屏?xí)r,頁面會(huì)被視為 “隱藏”,觸發(fā) visibilitychangedocument.hidden = true);解鎖后恢復(fù),觸發(fā) visible。

visibilitychange 事件是 H5 頁面監(jiān)聽 “前臺(tái) / 后臺(tái)切換” 的最優(yōu)方案,具有以下優(yōu)勢:

  • 原生支持:無需依賴任何 SDK(包括微信 / 企業(yè)微信),兼容性極佳。
  • 精準(zhǔn)可靠:能覆蓋 “切 App、切換標(biāo)簽頁、鎖屏” 等所有頁面可見性變化場景。
  • 用法簡單:通過 document.hidden 或 visibilityState 即可判斷狀態(tài),代碼邏輯清晰。

缺點(diǎn):無法區(qū)分隱藏原因

是的,你沒看錯(cuò),先前講到的只是常規(guī)情況下用戶手動(dòng)切換后臺(tái)的觸發(fā), 但是在一些場景下還是要慎用

1. 無法區(qū)分 “切后臺(tái)” 的具體原因

visibilitychange 只能判斷頁面 “可見” 或 “隱藏”,但無法區(qū)分隱藏的具體場景,例如:

  • 用戶是 “切換到其他 App” 還是 “切換到瀏覽器的其他標(biāo)簽頁”?
  • 是 “手機(jī)鎖屏” 還是 “瀏覽器窗口最小化”?
  • 是 “分享到微信好友后暫時(shí)離開” 還是 “徹底關(guān)閉頁面”?

2. 部分瀏覽器 / 場景下觸發(fā)時(shí)機(jī)不精準(zhǔn)

  • 微信 / 支付寶等 App 內(nèi)置瀏覽器:在某些操作(如點(diǎn)擊分享、拉起原生組件)時(shí),可能會(huì)出現(xiàn) “短暫隱藏再恢復(fù)” 的誤觸發(fā)。例如,在微信中點(diǎn)擊 “分享到朋友圈”,頁面會(huì)先切后臺(tái)(觸發(fā) hidden),分享完成后切回前臺(tái)(觸發(fā) visible),但用戶實(shí)際并未離開頁面,可能干擾業(yè)務(wù)邏輯(如暫停的視頻被誤觸發(fā)播放 / 暫停)。
  • iOS 端的特殊行為:在 iOS Safari 中,當(dāng)頁面處于后臺(tái)且內(nèi)存不足時(shí),瀏覽器可能會(huì)凍結(jié)頁面 JS 執(zhí)行,導(dǎo)致 visibilitychange 事件在頁面恢復(fù)時(shí)延遲觸發(fā),或部分邏輯(如定時(shí)器)無法正常執(zhí)行。

3. 無法監(jiān)聽 “頁面關(guān)閉” 的最終狀態(tài)

visibilitychange 的 unloaded 狀態(tài)在多數(shù)瀏覽器中支持不佳,且頁面真正關(guān)閉時(shí)(如用戶點(diǎn)擊關(guān)閉標(biāo)簽頁),visibilitychange 可能與 beforeunload、pagehide 事件順序混亂,難以可靠判斷 “用戶是否徹底離開”。例如,用戶關(guān)閉標(biāo)簽頁時(shí),hidden 會(huì)先變?yōu)?nbsp;true,但此時(shí)頁面即將卸載,后續(xù)邏輯(如上報(bào)數(shù)據(jù))可能因頁面關(guān)閉而中斷。

4. 對(duì) “部分可見” 狀態(tài)的判斷有限

document.visibilityState = 'visible' 表示頁面 “至少部分可見”(如瀏覽器窗口只露出一小塊),但無法判斷頁面是否 “完全可見”(如被其他窗口遮擋了大部分)。如果業(yè)務(wù)需要精確判斷 “用戶是否正在全屏瀏覽”,visibilitychange 無法滿足,需結(jié)合 document.fullscreenElement 等 API 輔助判斷。

用戶是 “切換到其他 App” 還是 “切換到瀏覽器的其他標(biāo)簽頁”?

是 “手機(jī)鎖屏” 還是 “瀏覽器窗口最小化”

是 “分享到微信好友后暫時(shí)離開” 還是 “徹底關(guān)閉頁面”?

上面三種是常見的場景,通常可以這樣的輔助方法進(jìn)行判斷

一、區(qū)分 “切換到其他 App” vs “切換到瀏覽器其他標(biāo)簽頁”

核心思路:利用瀏覽器標(biāo)簽頁的 “焦點(diǎn)狀態(tài)” 和 “頁面可見性” 的關(guān)聯(lián)性

  • 切換到瀏覽器其他標(biāo)簽頁時(shí):頁面失去焦點(diǎn)(window.blur)且可見性變?yōu)殡[藏(document.hidden = true),但瀏覽器進(jìn)程仍在運(yùn)行,setTimeout 等定時(shí)器可能繼續(xù)執(zhí)行(取決于瀏覽器優(yōu)化策略)。
  • 切換到其他 App時(shí):頁面不僅隱藏(document.hidden = true),還可能伴隨瀏覽器進(jìn)程被 “凍結(jié)”(尤其是移動(dòng)端),定時(shí)器執(zhí)行會(huì)延遲或暫停。

輔助判斷方法:

  1. 結(jié)合 focus/blur 事件與定時(shí)器延遲檢測(一般情況可用,所以慎用)

    let isTabSwitch = false;
    let timer;
    
    // 監(jiān)聽可見性變化
    document.addEventListener('visibilitychange', () => {
      if (document.hidden) {
        // 頁面隱藏時(shí)啟動(dòng)定時(shí)器,檢測延遲
        timer = setTimeout(() => {
          // 若定時(shí)器延遲超過100ms,大概率是切換到其他App(瀏覽器被凍結(jié))
          console.log('可能切換到其他App');
        }, 100);
      } else {
        clearTimeout(timer);
        // 頁面恢復(fù)時(shí),若之前觸發(fā)了blur且無明顯延遲,可能是切換標(biāo)簽頁
        if (isTabSwitch) {
          console.log('可能切換到瀏覽器其他標(biāo)簽頁');
          isTabSwitch = false;
        }
      }
    });
    
    // 監(jiān)聽焦點(diǎn)變化
    window.addEventListener('blur', () => {
      if (document.hidden) {
        isTabSwitch = true; // 隱藏時(shí)失去焦點(diǎn),可能是切換標(biāo)簽頁
      }
    });
    
    • 原理:切換標(biāo)簽頁時(shí),瀏覽器仍在前臺(tái)運(yùn)行,定時(shí)器延遲較小;切換到其他 App 時(shí),瀏覽器進(jìn)入后臺(tái),定時(shí)器可能被延遲執(zhí)行。

二、區(qū)分 “手機(jī)鎖屏” vs “瀏覽器窗口最小化”

核心思路:利用 “鎖屏” 的特殊性 —— 通常伴隨設(shè)備屏幕關(guān)閉,而 “窗口最小化” 僅窗口不可見

  • 手機(jī)鎖屏?xí)r:屏幕完全關(guān)閉,瀏覽器可能觸發(fā) visibilitychange 且后續(xù)操作(如觸摸事件)完全失效。
  • 瀏覽器窗口最小化(PC 端):屏幕仍亮,只是窗口不可見。

輔助判斷方法:

  1. 結(jié)合 screen 對(duì)象的亮度或喚醒狀態(tài)(移動(dòng)端有限支持):

    document.addEventListener('visibilitychange', () => {
      if (document.hidden) {
        // 檢測屏幕是否變暗(部分設(shè)備支持)
        if (typeof screen.brightness !== 'undefined' && screen.brightness < 0.1) {
          console.log('可能是手機(jī)鎖屏');
        } else {
          console.log('可能是瀏覽器窗口最小化');
        }
      }
    });
    
    • 注意:screen.brightness 兼容性較差(主要支持安卓部分瀏覽器),iOS 基本不支持。
  2. 監(jiān)聽 touchstart 事件是否失效(移動(dòng)端):鎖屏后,頁面無法接收觸摸事件,可在頁面恢復(fù)可見時(shí)檢測是否有 “鎖屏期間的觸摸記錄”(無記錄則可能是鎖屏):

    let hasTouchDuringHidden = false;
    document.addEventListener('touchstart', () => {
      if (document.hidden) {
        hasTouchDuringHidden = true;
      }
    });
    
    document.addEventListener('visibilitychange', () => {
      if (!document.hidden) {
        if (!hasTouchDuringHidden) {
          console.log('可能是手機(jī)鎖屏(期間無觸摸)');
        } else {
          console.log('可能是窗口最小化(期間可能有觸摸其他窗口)');
          hasTouchDuringHidden = false;
        }
      }
    });
    

三、區(qū)分 “分享到微信好友后暫時(shí)離開” vs “徹底關(guān)閉頁面”

核心思路:利用 “分享” 操作的前置行為(如點(diǎn)擊分享按鈕)和頁面生命周期差異

  • 分享到微信好友后暫時(shí)離開:用戶點(diǎn)擊分享按鈕 → 頁面隱藏 → 分享完成后用戶可能返回,頁面會(huì)再次觸發(fā) visible。
  • 徹底關(guān)閉頁面:頁面隱藏后,會(huì)接著觸發(fā) pagehide 或 beforeunload 事件,且不會(huì)再恢復(fù) visible。

輔助判斷方法:

  1. 監(jiān)聽微信分享按鈕的點(diǎn)擊事件(微信 H5 場景):在微信環(huán)境中,用戶分享前通常會(huì)點(diǎn)擊自定義的 “分享按鈕”,可通過該行為標(biāo)記 “可能是分享導(dǎo)致的離開”:

    let isSharing = false;
    // 假設(shè)分享按鈕id為shareBtn
    document.getElementById('shareBtn').addEventListener('click', () => {
      isSharing = true; // 標(biāo)記用戶觸發(fā)了分享操作
    });
    
    document.addEventListener('visibilitychange', () => {
      if (document.hidden) {
        if (isSharing) {
          console.log('可能是分享到微信好友后暫時(shí)離開');
          // 30秒后若未恢復(fù)可見,視為可能關(guān)閉頁面
          setTimeout(() => {
            if (document.hidden) {
              console.log('分享后未返回,可能已關(guān)閉頁面');
              isSharing = false;
            }
          }, 30000);
        } else {
          console.log('可能是其他原因關(guān)閉頁面');
        }
      } else {
        if (isSharing) {
          console.log('分享后返回頁面');
          isSharing = false;
        }
      }
    });
    
  2. 結(jié)合 pagehide 事件判斷頁面是否卸載:徹底關(guān)閉頁面時(shí),pagehide 事件會(huì)在 visibilitychange 之后觸發(fā),可通過該事件確認(rèn) “頁面已關(guān)閉”:

    let isPageClosed = false;
    window.addEventListener('pagehide', () => {
      isPageClosed = true;
      console.log('頁面已關(guān)閉');
    });
    
    document.addEventListener('visibilitychange', () => {
      if (document.hidden && !isPageClosed) {
        console.log('頁面隱藏但未關(guān)閉(可能是分享后暫時(shí)離開)');
      }
    });
    

    總結(jié):

    沒有絕對(duì)的完美,只有不斷地完善,當(dāng)后臺(tái)切換時(shí)還是要盡可能的與原有應(yīng)用進(jìn)行事件關(guān)聯(lián)才會(huì)更準(zhǔn)確的判斷用戶的操作行為。

到此這篇關(guān)于h5后臺(tái)切換檢測利用visibilitychange的缺點(diǎn)超詳細(xì)分析的文章就介紹到這了,更多相關(guān)h5后臺(tái)切換檢測visibilitychange內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

奇台县| 大余县| 昌平区| 石狮市| 鲁山县| 楚雄市| 商河县| 平舆县| 洛扎县| 忻城县| 平江县| 西城区| 四会市| 页游| 孟州市| 江阴市| 绵阳市| 衡水市| 郴州市| 乐昌市| 丁青县| 广灵县| 富锦市| 保靖县| 平果县| 伽师县| 高要市| 民权县| 克拉玛依市| 延安市| 横山县| 玉环县| 乌兰浩特市| 富顺县| 商南县| 崇明县| 碌曲县| 黎平县| 宜丰县| 石林| 台山市|