Bir tarayıcı penceresinin etkin olmadığını tespit etmenin bir yolu var mı?


585

Periyodik olarak etkinlik yapan JavaScript'im var. Kullanıcı siteye bakmadığında (yani pencere veya sekmenin odağı yoksa), çalıştırmamak iyi olur.

JavaScript kullanarak bunu yapmanın bir yolu var mı?

Referans noktam: Kullandığınız pencere etkin değilse Gmail Sohbet bir ses çalar.


8
Aşağıdaki yanıtlardan memnun olmayanlar için requestAnimationFrameAPI'ya bakın veya pencere görünmediğinde setTimeout/ sıklığının setIntervalazaltıldığı modern özelliği kullanın (örneğin, Chrome'da 1 sn).
Rob W

2
document.body.onblur = function (e) {console.log ('lama');} odaklanmamış elemanlar için çalıştı.
WhyMe

2
W3C Sayfa Görünürlüğü API'sını kullanan ve onu desteklemeyen tarayıcılara geri dönen / görüntüleyen tarayıcılar arası uyumlu bir çözüm için bu cevaba bakın . blurfocus
Mathias Bynens

2
Aşağıdaki cevapların% 80'i bu sorunun cevabı değildir . Soru şu anda aktif değil, ancak aşağıdaki tonlarca cevap görünür değil, bu sorunun yanıtı değil.
Tartışmalı

Yanıtlar:


691

Bu cevabı ilk olarak yazdığından beri , W3C sayesinde yeni bir şartname tavsiye durumuna ulaştı . Sayfa Görünürlük API'sı (on MDN'yi ) Artık, sayfa kullanıcıya gizli olduğunda daha doğru algılamasını sağlar.

document.addEventListener("visibilitychange", onchange);

Mevcut tarayıcı desteği:

  • Chrome 13+
  • Internet Explorer 10 ve üstü sürümler
  • Firefox 10+
  • Opera 12.10+ [ notları okuyun ]

Aşağıdaki kod, uyumsuz tarayıcılarda daha az güvenilir bulanıklaştırma / odaklama yöntemine geri döner:

(function() {
  var hidden = "hidden";

  // Standards:
  if (hidden in document)
    document.addEventListener("visibilitychange", onchange);
  else if ((hidden = "mozHidden") in document)
    document.addEventListener("mozvisibilitychange", onchange);
  else if ((hidden = "webkitHidden") in document)
    document.addEventListener("webkitvisibilitychange", onchange);
  else if ((hidden = "msHidden") in document)
    document.addEventListener("msvisibilitychange", onchange);
  // IE 9 and lower:
  else if ("onfocusin" in document)
    document.onfocusin = document.onfocusout = onchange;
  // All others:
  else
    window.onpageshow = window.onpagehide
    = window.onfocus = window.onblur = onchange;

  function onchange (evt) {
    var v = "visible", h = "hidden",
        evtMap = {
          focus:v, focusin:v, pageshow:v, blur:h, focusout:h, pagehide:h
        };

    evt = evt || window.event;
    if (evt.type in evtMap)
      document.body.className = evtMap[evt.type];
    else
      document.body.className = this[hidden] ? "hidden" : "visible";
  }

  // set the initial state (but only if browser supports the Page Visibility API)
  if( document[hidden] !== undefined )
    onchange({type: document[hidden] ? "blur" : "focus"});
})();

onfocusinve onfocusoutedilir IE 9 için gerekli ve alt tüm diğerleri faydalanmak ederken, onfocusve onbluriOS kullanımlar hariç olmak üzere, onpageshowve onpagehide.


1
@bellpeace: IE yayılmalı focusinve focusoutiframe'den üst pencereye gitmelidir . Daha yeni tarayıcılar için, her iframe nesnesindeki focusve blurolaylarını işlemeniz yeterlidir window. En azından daha yeni tarayıcılarda bu durumları kapsayacak şekilde eklediğim güncellenmiş kodu kullanmalısınız.
Andy E

3
@JulienKronegg: Bu yüzden cevabım, cevabımı yazdıktan sonra çalışma taslağı durumuna giren Sayfa Görünürlüğü API'sından özellikle bahsediyor. Odak / bulanıklaştırma yöntemleri, eski tarayıcılar için sınırlı işlevsellik sağlar. Cevabınızdaki gibi diğer olaylara bağlanma, bundan daha fazlasını kapsamaz ve davranışsal farklılıklar riski daha fazladır (IE, imlecin altında bir pencere açıldığında mouseout'u ateşlememesi gibi). Kullanıcıya güncellemelerin sayfa hareketsizliği nedeniyle daha az sıklıkta olabileceğini belirten bir mesaj veya simge görüntülemek için daha uygun bir işlem olacağını öneririm.
Andy E

6
@AndyE Bu çözümü krom üzerinde denedim. Sekmeleri değiştirirsem çalışır, ancak pencereleri değiştirirsem işe yaramaz (ALT + sekmesi). Olmalı mı? İşte bir keman - jsfiddle.net/8a9N6/17
Tony Lâmpada

2
@Heliodor: Cevaptaki kodu şimdilik asgari düzeyde tutmak istiyorum. Uygulayıcılar vücut üzerinde bir sınıf oluşturmaktan kaçınmak ve tamamen farklı bir eylemde bulunmak isteyebileceğinden (bir zamanlayıcıyı durdurmak ve başlatmak gibi) asla kes ve yapıştır tam bir çözüm olarak tasarlanmamıştır.
Andy E

8
@AndyE Çözümünüz yalnızca kullanıcı sekmeleri değiştirirse veya pencereyi simge durumuna küçültür / büyütürse işe yarar. Ancak, kullanıcı sekmeyi etkin bırakır, ancak görev çubuğundan başka bir programı en üst düzeye çıkarırsa onchange olayı tetiklenmez. Bu senaryo için bir çözüm var mı? Teşekkürler!
user1491636

132

Çünkü tüm yapmanız gereken bu jQuery kullanmak istiyorsunuz:

$(window).blur(function(){
  //your code here
});
$(window).focus(function(){
  //your code
});

Ya da en azından benim için çalıştı.


1
benim için iframe içinde iki kez bu çağrı
msangel

Firefox'ta, kundakçı konsolunun içine tıklarsanız (aynı sayfada), windowdoğru olan odak kaybedilir, ancak doğru olan şey neye ihtiyacınız olduğuna bağlı olmayabilir.
Majid Fouladpour

21
Bu, artık modern tarayıcıların mevcut sürümleri için geçerli değildir, bkz. Onaylı cevap (Sayfa Görünürlüğü API'sı)
Jon z

Bu çözüm iPad'de çalışmıyor Lütfen "pageshow" etkinliğini kullanın
ElizaS

Sayfa yüklendiğinde hem BLUR hem de FOCUS tetiklenir. Sayfamdan yeni bir pencere açtığımda hiçbir şey olmuyor ama yeni pencere kapatıldıktan sonra her iki olay da tetikleniyor: / (IE8 kullanarak)
SearchForKnowledge

49

Kullanıcının HTML sayfasını görüp göremeyeceğini belirlemek için kullanılan 3 tipik yöntem vardır, ancak bunların hiçbiri mükemmel bir şekilde çalışmaz:

  • W3C Sayfa Görünürlük API'sı bunu gerekiyordu (: Firefox 10, MSIE 10, Chrome 13 beri desteklenir). Ancak, bu API yalnızca tarayıcı sekmesi tamamen geçersiz kılındığında (ör. Kullanıcı bir sekmeden diğerine değiştiğinde) olayları artırır. Görünürlük% 100 doğrulukla belirlenemediğinde API olayları artırmaz (örneğin, başka bir uygulamaya geçmek için Alt + Tab).

  • Odak / bulanıklaştırma tabanlı yöntemleri kullanmak size çok sayıda yanlış pozitif verir. Örneğin, kullanıcı tarayıcı penceresinin üstünde daha küçük bir pencere görüntülerse, tarayıcı penceresi odağı kaybeder ( onbluryükseltilir), ancak kullanıcı yine de görebilir (bu yüzden yine de yenilenmesi gerekir). Ayrıca bkz. Http://javascript.info/tutorial/focus

  • Kullanıcı etkinliğine (fare hareketi, tıklamalar, yazılan tuş) güvenmek size çok fazla yanlış pozitif verir. Yukarıdaki durumu veya video izleyen bir kullanıcıyı düşünün.

Yukarıda açıklanan kusurlu davranışları iyileştirmek için, 3 yöntemin bir kombinasyonunu kullanıyorum: W3C Görünürlük API'sı, daha sonra yanlış pozitif oranı azaltmak için odaklama / bulanıklık ve kullanıcı etkinliği yöntemleri. Bu, aşağıdaki olayları yönetmenizi sağlar:

  • Tarayıcı sekmesini diğerine değiştirme (W3C Sayfa Görünürlüğü API'sı sayesinde% 100 doğruluk)
  • Sayfa potansiyel olarak başka bir pencere tarafından gizlenmiş, örneğin Alt + Tab nedeniyle (olasılıklı =% 100 doğru değil)
  • Kullanıcının ilgisi potansiyel olarak HTML sayfasına odaklanmadı (olasılıklı =% 100 doğru değil)

Bu şekilde çalışır: belge odağı kaybettiğinde, pencerenin görünür olup olmadığını belirlemek için belge üzerindeki kullanıcı etkinliği (fare hareketi gibi) izlenir. Sayfa görünürlüğü olasılığı, sayfadaki son kullanıcı etkinliğinin süresi ile ters orantılıdır: kullanıcı belgede uzun süre etkinlik yapmazsa, sayfa büyük olasılıkla görünmez. Aşağıdaki kod W3C Sayfa Görünürlüğü API'sını taklit eder: aynı şekilde davranır, ancak yanlış pozitif oranı küçüktür. Birden çok kasalı olma avantajına sahiptir (Firefox 5, Firefox 10, MSIE 9, MSIE 7, Safari 5, Chrome 9 üzerinde test edilmiştir).

    <div id = "x"> </div>

    <Script>
    / **
    İşleyiciyi verilen nesnenin olaya kaydeder.
    @param olayı artıracak nesneye itiraz et
    Etkinlik türünü yazın: tıklayın, tuşa basın, fareyle üzerine gelme, ...
    @param fn olay işleyici işlevi
    @param isCapturing olay modunu ayarlar (true = yakalama olayı, false = köpürme olayı)
    olay giderici doğru şekilde takılmışsa @return true
    * /
    function addEvent (obj, evType, fn, isCapturing) {
      if (isCapturing == null) isCapturing = false; 
      if (obj.addEventListener) {
        // Firefox
        obj.addEventListener (evType, fn, isCapturing);
        geri dönüş;
      } else if (obj.attachEvent) {
        // MSIE
        var r = obj.attachEvent ('on' + evType, fn);
        dönüş r;
      } Başka {
        yanlış döndür;
      }
    }

    // potansiyel sayfa görünürlüğü değişikliğine kaydolun
    addEvent (belge, "potansiyel görünürlük değişimi", işlev (olay) {
      document.getElementById ("x"). innerHTML + = "potansiyelVisilityChange: potansiyelHidden =" + document.potentialHidden + ", document.potentiallyHiddenSince =" + document.potentiallyHiddenSince + "s <br>";
    });

    // W3C Sayfa Görünürlük API'sına kaydolun
    var gizli = boş;
    var visibilityChange = null;
    if (typeof document.mozHidden! == "tanımsız") {
      "MozHidden" = gizli;
      visibilityChange = "mozvisibilitychange";
    } else if (typeof document.msHidden! == "tanımsız") {
      "MsHidden" = gizli;
      visibilityChange "msvisibilitychange" =;
    } else if (typeof document.webkitHidden! == "tanımsız") {
      = "WebkitHidden" gizli;
      visibilityChange "webkitvisibilitychange" =;
    } else if (typeof document.hidden! == "gizli") {
      = "Gizli" gizli;
      visibilityChange = "visibilitychange";
    }
    if (hidden! = null && visibilityChange! = null) {
      addEvent (belge, visibilityChange, function (event) {
        document.getElementById ("x"). innerHTML + = visibilityChange + ":" + gizli + "=" + belge [gizli] + "<br>";
      });
    }


    var potansiyelPageVisibility = {
      pageVisibilityChangeThreshold: 3 * 3600, // saniye olarak
      init: function () {
        işlev kümesiAsNotHidden () {
          var dispatchEventRequired = document.potentialHidden;
          document.potentialHidden yanlış =;
          document.potentiallyHiddenSince = 0;
          if (dispatchEventRequired) dispatchPageVisibilityChangeEvent ();
        }

        function initPotentiallyHiddenDetection () {
          if (! hasFocusLocal) {
            // pencerenin odağı yok => pencerede kullanıcı etkinliğini kontrol et
            lastActionDate = yeni Tarih ();
            if (timeoutHandler! = null) {
              clearTimeout (timeoutHandler);
            }
            timeoutHandler = setTimeout (checkPageVisibility, potansiyelPageVisibility.pageVisibilityChangeThreshold * 1000 + 100); // Firefox altında yuvarlama sorunlarını önlemek için +100 ms
          }
        }

        function dispatchPageVisibilityChangeEvent () {
          unifiedVisilityChangeEventDispatchAllowed yanlış =;
          var evt = document.createEvent ("Olay");
          evt.initEvent ("potansiyel görünürlük değişimi", doğru, doğru);
          document.dispatchEvent (EVT);
        }

        function checkPageVisibility () {
          var potansiyelHiddenDuration = (hasFocusLocal || lastActionDate == null? 0: Math.floor ((yeni Tarih (). getTime () - lastActionDate.getTime ()) / 1000));
                                        document.potentiallyHiddenSince = potentialHiddenDuration;
          if (potansiyelHiddenDuration> = potansiyelSayfaVisibility.pageVisibilityChangeThreshold &&! document.potentialHidden) {
            // sayfa görünürlüğü değişiklik eşiği raiched => çift yükselt
            document.potentialHidden doğru =;
            dispatchPageVisibilityChangeEvent ();
          }
        }

        var lastActionDate = null;
        var hasFocusLocal = true;
        var hasMouseOver = true;
        document.potentialHidden yanlış =;
        document.potentiallyHiddenSince = 0;
        var timeoutHandler = null;

        addEvent (belge, "sayfa gösterisi", işlev (etkinlik) {
          document.getElementById ( "x") innerHTML + = "pageshow / doc: Ürün".;
        });
        addEvent (belge, "sayfa gizleme", işlev (olay) {
          document.getElementById ( "x") innerHTML + = "pagehide / doc: Ürün".;
        });
        addEvent (pencere, "sayfa gösterisi", işlev (olay) {
          document.getElementById ( "x") innerHTML + = "pageshow / kazan: <br>".; // sayfa ilk gösterildiğinde kaldırıldı
        });
        addEvent (pencere, "sayfa gizleme", işlev (olay) {
          document.getElementById ( "x") innerHTML + = "pagehide / kazan: <br>".; // yükseltilmedi
        });
        addEvent (belge, "fare kaldırma", işlev (olay) {
          lastActionDate = yeni Tarih ();
        });
        addEvent (belge, "fareyle üzerine gelme", ​​işlev (olay) {
          hasMouseOver doğru =;
          ) (SetAsNotHidden;
        });
        addEvent (belge, "fare kapanı", işlev (olay) {
          hasMouseOver yanlış =;
          initPotentiallyHiddenDetection ();
        });
        addEvent (pencere, "bulanıklaştırma", işlev (olay) {
          hasFocusLocal yanlış =;
          initPotentiallyHiddenDetection ();
        });
        addEvent (pencere, "odak", işlev (olay) {
          hasFocusLocal doğru =;
          ) (SetAsNotHidden;
        });
        ) (SetAsNotHidden;
      }
    }

    potentialPageVisibility.pageVisibilityChangeThreshold = 4; // test için 4 saniye
    potentialPageVisibility.init ();
    </ Script>

Şu anda yanlış pozitif olmadan çalışan bir çapraz tarayıcı çözümü olmadığından, web sitenizdeki periyodik etkinliği devre dışı bırakmayı daha iyi düşünmelisiniz.


Undefined anahtar sözcüğü yerine 'undefined' dizesinde katı bir karşılaştırma işleci kullanmak yukarıdaki kodda yanlış pozitiflere neden olmaz mı?
Jonathon

@ kiran: Aslında Alt + Tab ile çalışıyor. Alt + Sekme yaptığınızda sayfanın gizlenip gizlenmediğini belirleyemezsiniz, çünkü sayfanızın tamamen gizlendiğini garanti edemeyeceğiniz için daha küçük bir pencereye geçebilirsiniz. Bu yüzden "potansiyel olarak gizli" kavramını kullanıyorum (örnekte eşik 4 saniyeye ayarlanmış, bu yüzden Alt + Tab kullanarak en az 4 saniye boyunca başka bir pencereye geçmeniz gerekiyor). Ancak yorumunuz cevabın o kadar net olmadığını gösteriyor, bu yüzden yeniden yazdım.
Julien Kronegg

@JulienKronegg Bence bu henüz en iyi çözüm. Bununla birlikte, yukarıdaki kod son derece bazı yeniden düzenleme ve soyutlamalara ihtiyaç duyar. Neden GitHub'a yüklemiyor ve topluluğun yeniden düzenlenmesine izin vermiyorsun?
Jacob

1
@Jacob Çözümümü beğendiğiniz için mutluyum. Kendinizi bir GitHub projesine tanıtmaktan çekinmeyin. Kodu lisansla birlikte veririm Creative Commons BY creativecommons.org/licenses/by/4.0
Julien Kronegg

26

GitHub'da düzgün bir kütüphane var:

https://github.com/serkanyersen/ifvisible.js

Misal:

// If page is visible right now
if( ifvisible.now() ){
  // Display pop-up
  openPopUp();
}

Sahip olduğum tüm tarayıcılarda 1.0.1 sürümünü test ettim ve çalıştığını onaylayabilirim:

  • IE9, IE10
  • FF 26.0
  • Chrome 34.0

... ve muhtemelen tüm yeni sürümler.

Tam olarak çalışmaz:

  • IE8 - her zaman sekmenin / pencerenin şu anda etkin olduğunu belirtin ( .now()her zaman truebenim için geri döner )

Kabul edilen cevap IE9'da sorunlara neden oldu. Bu kütüphane harika çalışıyor.
Tom Teman

20

Kullanımı: Sayfa Görünürlüğü API'sı

document.addEventListener( 'visibilitychange' , function() {
    if (document.hidden) {
        console.log('bye');
    } else {
        console.log('well back');
    }
}, false );

Kullanabilirmiyim ? http://caniuse.com/#feat=pagevisibility


Soru, sayfa görünürlüğü ile ilgili değildir. Aktif / aktif değil
gman

Bence OP
ide'nin

1
Ben de ide'den bahsetmiyorum. Başka bir uygulamaya alt-tabbing / cmd-tabbing'den bahsediyorum. Aniden sayfa etkin değil. Sayfa görünürlüğü API'si, sayfanın etkin olup olmadığını bilmeme yardımcı olmaz, yalnızca görünür olmadığında bana yardımcı olur.
gman

18

Uygulamam için bir Comet Chat oluşturuyorum ve başka bir kullanıcıdan mesaj aldığımda kullanıyorum:

if(new_message){
    if(!document.hasFocus()){
        audio.play();
        document.title="Have new messages";
    }
    else{
        audio.stop();
        document.title="Application Name";
    } 
}

2
IE6'ya geri
Paul Cooper

4
document.hasFocus()bunu yapmanın en temiz yoludur. Görünürlük API'sini veya olayı kullanan veya çeşitli düzeylerde kullanıcı etkinliği / etkinlik eksikliği arayan diğer tüm yollar aşırı karmaşık hale gelir ve kenar vakaları ve deliklerle doludur. basit bir aralığa koyun ve sonuçlar değiştiğinde özel bir etkinlik oluşturun. Örnek: jsfiddle.net/59utucz6/1
danatcofo 29:17

1
Verimli ve diğer çözümlerin aksine, başka bir tarayıcı sekmesine veya penceresine ve hatta farklı bir uygulamaya geçtiğinizde doğru geri bildirim sağlar.
ow3n

Şüphe yok, onun en temiz yolu, ancak firefox'ta çalışmıyor
hardik chugh

1
Chrome Dev araçlarını açarsam document.hasFocus () öğesi false değerine eşittir. Veya tarayıcının üst panelini tıklasanız bile aynı şey olur. Bu çözümün video, animasyon, vb. Duraklatmaya uygun olduğundan emin değilim
tylik

16

Topluluk wiki yanıtını kullanmaya başladım, ancak bunun Chrome'daki alt sekme olaylarını tespit etmediğini fark ettim. Bunun nedeni, kullanılabilir ilk etkinlik kaynağını kullanması ve bu durumda Chrome'da alt sekmeyi izlemeyen sayfa görünürlüğü API'sı olmasıdır.

Sayfa odak değişiklikleri için tüm olası olayları takip etmek için komut dosyasını biraz değiştirmeye karar verdim . İşte size bırakabileceğiniz bir işlev:

function onVisibilityChange(callback) {
    var visible = true;

    if (!callback) {
        throw new Error('no callback given');
    }

    function focused() {
        if (!visible) {
            callback(visible = true);
        }
    }

    function unfocused() {
        if (visible) {
            callback(visible = false);
        }
    }

    // Standards:
    if ('hidden' in document) {
        document.addEventListener('visibilitychange',
            function() {(document.hidden ? unfocused : focused)()});
    }
    if ('mozHidden' in document) {
        document.addEventListener('mozvisibilitychange',
            function() {(document.mozHidden ? unfocused : focused)()});
    }
    if ('webkitHidden' in document) {
        document.addEventListener('webkitvisibilitychange',
            function() {(document.webkitHidden ? unfocused : focused)()});
    }
    if ('msHidden' in document) {
        document.addEventListener('msvisibilitychange',
            function() {(document.msHidden ? unfocused : focused)()});
    }
    // IE 9 and lower:
    if ('onfocusin' in document) {
        document.onfocusin = focused;
        document.onfocusout = unfocused;
    }
    // All others:
    window.onpageshow = window.onfocus = focused;
    window.onpagehide = window.onblur = unfocused;
};

Şöyle kullanın:

onVisibilityChange(function(visible) {
    console.log('the page is now', visible ? 'focused' : 'unfocused');
});

Bu sürüm, tüm farklı görünürlük olaylarını dinler ve bunlardan herhangi biri değişikliğe neden olursa geri arama yapar. focusedVe unfocusedişleyicileri birden API'leri aynı görünürlük değişikliği yakalarsa geri arama birden çok kez denilen olmadığından emin olun.


Örneğin Chrome'da hem document.hiddenve bulunur document.webkitHidden. Olmadan elseyılında ifinşaat biz 2 geri arama çağrıları doğru olsun ki?
Christiaan Westerbeek

@ChristiaanWesterbeek Bu iyi bir nokta, bunu düşünmemiştim! Bu
yazıyı

Hey bir dakika: ChristiaanWesterbeek tarafından önerilen ve aslında @ 1.21Gigawatts tarafından eklenen "başkasını" eklemek için düzenleme iyi bir fikir gibi görünmüyor: Daniel'in fikrinin orijinal satın alımını yeniyor, bu da tüm desteklenenleri denemek paralel yöntemler. Geri arama işleminin iki kez çağrılma riski yoktur çünkü odaklanmış () ve odaklanmamış () hiçbir şey değişmediğinde fazladan çağrıları bastırır. Gerçekten ilk döneme dönmeliyiz gibi görünüyor.
Louis Semprini

@ LouisSemprini harika bir yakalama. Kodun orijinal niyetini unutmuştum! Orijinali geri yükledim ve bir açıklama ekledim!
Daniel Buckmaster

bugünden itibaren bunu kontrol ederken, en azından Chrome 78 + macos'ta alt + sekmesini algılamaz
Hugo Gresse

7

Bu gerçekten zor. Aşağıdaki gereksinimler göz önüne alındığında bir çözüm yok gibi görünüyor.

  • Sayfa üzerinde kontrolünüz olmayan iframe'ler içeriyor
  • Bir SEKME değişikliği (ctrl + sekme) veya bir pencere değişikliği (alt + sekme) tarafından tetiklenen değişikliğe bakılmaksızın görünürlük durumu değişikliğini izlemek istiyorsunuz

Bunun nedeni şu:

  • Görünürlük API'si sayfası, sekme değişikliğini (iframe'lerde bile) güvenilir bir şekilde söyleyebilir, ancak kullanıcı pencereleri değiştirdiğinde size söyleyemez.
  • Pencere bulanıklaştırma / odaklama olaylarını dinlemek, iframe'in odağı olmadığı sürece alt + sekmeleri ve ctrl + sekmelerini algılayabilir.

Bu kısıtlamalar göz önüne alındığında, aşağıdakileri birleştiren bir çözüm uygulamak mümkündür - Sayfa Görünürlük API'sı - pencere bulanıklaştırma / odaklama - document.activeElement

Bu şunları yapabilir:

  • 1) Üst sayfa odaklandığında ctrl + sekmesi: EVET
  • 2) iframe odaklandığında ctrl + sekmesi: EVET
  • 3) üst sayfa odaklandığında alt + sekmesi: EVET
  • 4) iframe odaklandığında alt + sekmesi: NO <- bummer

İframe odaklandığında, bulanıklaştırma / odaklama etkinlikleriniz hiç çağrılmaz ve Görünürlük API'sı sayfası alt + sekmesinde tetiklenmez.

@ AndyE'nin çözümünü geliştirdim ve bu (neredeyse iyi) çözümü burada uyguladım: https://dl.dropboxusercontent.com/u/2683925/estante-components/visibility_test1.html (üzgünüm, JSFiddle ile ilgili bir sorunum vardı).

Bu, Github'da da mevcuttur: https://github.com/qmagico/estante-components

Bu krom / krom üzerinde çalışır. Bu tür, iframe içeriğini yüklememesi dışında firefox'ta çalışır (neden herhangi bir fikir?)

Her neyse, son sorunu çözmek için (4), bunu yapmanın tek yolu iframe'deki bulanıklaştırma / odaklama olaylarını dinlemek. İframe'ler üzerinde biraz kontrolünüz varsa, bunu yapmak için postMessage API'sını kullanabilirsiniz.

https://dl.dropboxusercontent.com/u/2683925/estante-components/visibility_test2.html

Bunu hala yeterince tarayıcıyla test etmedim. Bunun işe yaramadığı hakkında daha fazla bilgi bulabilirseniz, lütfen aşağıdaki yorumlarda bana bildirin.


Testlerimde Android'de IE9, IE10 ve Chrome'da da çalıştı.
Tony Lâmpada

1

3
Tüm bu bağlantılar 404'ler :(
Daniel Buckmaster

6
var visibilityChange = (function (window) {
    var inView = false;
    return function (fn) {
        window.onfocus = window.onblur = window.onpageshow = window.onpagehide = function (e) {
            if ({focus:1, pageshow:1}[e.type]) {
                if (inView) return;
                fn("visible");
                inView = true;
            } else if (inView) {
                fn("hidden");
                inView = false;
            }
        };
    };
}(this));

visibilityChange(function (state) {
    console.log(state);
});

http://jsfiddle.net/ARTsinn/JTxQY/


5

bu benim için chrome 67, firefox 67,

if(!document.hasFocus()) {
    // do stuff
}

3

u kullanabilirsiniz:

(function () {

    var requiredResolution = 10; // ms
    var checkInterval = 1000; // ms
    var tolerance = 20; // percent


    var counter = 0;
    var expected = checkInterval / requiredResolution;
    //console.log('expected:', expected);

    window.setInterval(function () {
        counter++;
    }, requiredResolution);

    window.setInterval(function () {
        var deviation = 100 * Math.abs(1 - counter / expected);
        // console.log('is:', counter, '(off by', deviation , '%)');
        if (deviation > tolerance) {
            console.warn('Timer resolution not sufficient!');
        }
        counter = 0;
    }, checkInterval);

})();

3

HTML 5'te şunları da kullanabilirsiniz:

  • onpageshow: Pencere görünür olduğunda çalıştırılacak komut dosyası
  • onpagehide: Pencere gizlendiğinde çalıştırılacak komut dosyası

Görmek:


2
Bunun BFCache ile ilgili olduğunu düşünüyorum: kullanıcı Geri veya İleri'yi tıklattığında - sayfanın bilgisayar masaüstünün en üstünde olmasıyla ilgili değildir.
nonopolarite

2

Bu Andy E.'nin cevabının bir uyarlamasıdır.

Bu, örneğin yalnızca sayfa görünür ve odaklanmışsa, her 30 saniyede bir sayfayı yenilemek gibi bir görev yapar.

Görünürlük algılanamazsa, yalnızca odak kullanılır.

Kullanıcı sayfayı odaklarsa, hemen güncellenir

Herhangi bir ajax çağrısından sonra 30 saniye öncesine kadar sayfa tekrar güncellenmeyecek

var windowFocused = true;
var timeOut2 = null;

$(function(){
  $.ajaxSetup ({
    cache: false
  });
  $("#content").ajaxComplete(function(event,request, settings){
       set_refresh_page(); // ajax call has just been made, so page doesn't need updating again for 30 seconds
   });
  // check visibility and focus of window, so as not to keep updating unnecessarily
  (function() {
      var hidden, change, vis = {
              hidden: "visibilitychange",
              mozHidden: "mozvisibilitychange",
              webkitHidden: "webkitvisibilitychange",
              msHidden: "msvisibilitychange",
              oHidden: "ovisibilitychange" /* not currently supported */
          };
      for (hidden in vis) {
          if (vis.hasOwnProperty(hidden) && hidden in document) {
              change = vis[hidden];
              break;
          }
      }
      document.body.className="visible";
      if (change){     // this will check the tab visibility instead of window focus
          document.addEventListener(change, onchange,false);
      }

      if(navigator.appName == "Microsoft Internet Explorer")
         window.onfocus = document.onfocusin = document.onfocusout = onchangeFocus
      else
         window.onfocus = window.onblur = onchangeFocus;

      function onchangeFocus(evt){
        evt = evt || window.event;
        if (evt.type == "focus" || evt.type == "focusin"){
          windowFocused=true; 
        }
        else if (evt.type == "blur" || evt.type == "focusout"){
          windowFocused=false;
        }
        if (evt.type == "focus"){
          update_page();  // only update using window.onfocus, because document.onfocusin can trigger on every click
        }

      }

      function onchange () {
        document.body.className = this[hidden] ? "hidden" : "visible";
        update_page();
      }

      function update_page(){
        if(windowFocused&&(document.body.className=="visible")){
          set_refresh_page(1000);
        }
      }


  })();
  set_refresh_page();
})

function get_date_time_string(){
  var d = new Date();
  var dT = [];
  dT.push(d.getDate());
  dT.push(d.getMonth())
  dT.push(d.getFullYear());
  dT.push(d.getHours());
  dT.push(d.getMinutes());
  dT.push(d.getSeconds());
  dT.push(d.getMilliseconds());
  return dT.join('_');
}

function do_refresh_page(){

// do tasks here

// e.g. some ajax call to update part of the page.

// (date time parameter will probably force the server not to cache)

//      $.ajax({
//        type: "POST",
//        url: "someUrl.php",
//        data: "t=" + get_date_time_string()+"&task=update",
//        success: function(html){
//          $('#content').html(html);
//        }
//      });

}

function set_refresh_page(interval){
  interval = typeof interval !== 'undefined' ? interval : 30000; // default time = 30 seconds
  if(timeOut2 != null) clearTimeout(timeOut2);
  timeOut2 = setTimeout(function(){
    if((document.body.className=="visible")&&windowFocused){
      do_refresh_page();
    }
    set_refresh_page();
  }, interval);
}

Odak / bulanıklaştırma yöntemlerine güvenmek işe yaramıyor (size çok fazla yanlış pozitif veriyor), bkz. Stackoverflow.com/a/9502074/698168
Julien Kronegg

2

JQuery içermeyen bir çözüm için üç sayfa durumu hakkında bilgi sağlayan Visibility.js dosyasına göz atın

visible    ... page is visible
hidden     ... page is not visible
prerender  ... page is being prerendered by the browser

ve ayrıca setInterval için kolaylık

/* Perform action every second if visible */
Visibility.every(1000, function () {
    action();
});

/* Perform action every second if visible, every 60 sec if not visible */
Visibility.every(1000, 60*1000, function () {
    action();
});

Daha eski tarayıcılar için bir yedek (IE <10; iOS <7) de mevcuttur


tarayıcı desteği ne olacak? Şu an için krom, safari ve firefox'ta iyilik istiyoruz.
Selva Ganapathi

1

setInterval()Fare konumunu kontrol etmek ve son kontrole karşılaştırmak için biraz daha karmaşık bir yol kullanılabilir . Fare belirli bir süre hareket etmediyse, kullanıcı muhtemelen boşta kalır.

Bu yerine, kullanıcının boşta olup olmadığını söylemenin eklenen avantaja sahiptir sadece pencere etkin değilse kontrol ediyorum.

Birçok kişinin işaret ettiği gibi, bu kullanıcı veya tarayıcı penceresinin boş olup olmadığını kontrol etmek için her zaman iyi bir yol değildir, çünkü kullanıcı fareyi kullanmıyor veya video izliyor olabilir. Sadece boşta kalma durumunu kontrol etmenin olası bir yolunu öneriyorum.


30
Kullanıcının faresi yoksa.
user1686


Kullanıcı bir video izliyorsa bu zar
oynamaz

zamanlayıcıyı sıfırlamak ve fare dışı sorunu çözmek için onkeypress veya benzeri olayları kullanabilirsiniz. Tabii yine de kullanıcılar için değil işini aktif, vb bir video izlemek bir görüntüyü incelemek için sayfasına bakarak olur
joshuahedlund

1

Angular.js için, burada denetleyicinizin görünürlükteki bir değişikliğe tepki vermesini sağlayacak bir yönerge (kabul edilen cevaba göre) verilmiştir:

myApp.directive('reactOnWindowFocus', function($parse) {
    return {
        restrict: "A",
        link: function(scope, element, attrs) {
            var hidden = "hidden";
            var currentlyVisible = true;
            var functionOrExpression = $parse(attrs.reactOnWindowFocus);

          // Standards:
          if (hidden in document)
            document.addEventListener("visibilitychange", onchange);
          else if ((hidden = "mozHidden") in document)
            document.addEventListener("mozvisibilitychange", onchange);
          else if ((hidden = "webkitHidden") in document)
            document.addEventListener("webkitvisibilitychange", onchange);
          else if ((hidden = "msHidden") in document)
            document.addEventListener("msvisibilitychange", onchange);
          else if ("onfocusin" in document) {
                // IE 9 and lower:
            document.onfocusin = onshow;
                document.onfocusout = onhide;
          } else {
                // All others:
            window.onpageshow = window.onfocus = onshow;
                window.onpagehide = window.onblur = onhide;
            }

          function onchange (evt) {
                //occurs both on leaving and on returning
                currentlyVisible = !currentlyVisible;
                doSomethingIfAppropriate();
          }

            function onshow(evt) {
                //for older browsers
                currentlyVisible = true;
                doSomethingIfAppropriate();
            }

            function onhide(evt) {
                //for older browsers
                currentlyVisible = false;
                doSomethingIfAppropriate();
            }

            function doSomethingIfAppropriate() {
                if (currentlyVisible) {
                    //trigger angular digest cycle in this scope
                    scope.$apply(function() {
                        functionOrExpression(scope);
                    });
                }
            }
        }
    };

});

Bunu şu örnek gibi kullanabilirsiniz: <div react-on-window-focus="refresh()">Nerede refresh()Denetleyici kapsam dahilinde olursa olsun bir kapsam işlevi.


0

İşte sağlam, modern bir çözüm. (Kısa tatlı bir 👌🏽)

document.addEventListener("visibilitychange", () => {
  console.log( document.hasFocus() )
})

Bu, bir dinleyici, odak veya bulanıklık olabilecek herhangi bir görünürlük olayı tetiklendiğinde tetiklenecek şekilde ayarlanır.


0

Harekete istiyorsanız üzerine bütün tarayıcı bulanıklık : Ben yorumladığı gibi, eğer önerilen olaylar yangın tarayıcı kaybetmek odak hiçbiri. Benim fikrim bir döngü içinde saymak ve bir olay tetiklenirse sayacı sıfırlamaktır. Sayaç bir sınıra ulaşırsa başka bir sayfaya bir location.href yaparım. Bu, dev-tools üzerinde çalışıyorsanız da ateşlenir.

var iput=document.getElementById("hiddenInput");
   ,count=1
   ;
function check(){
         count++;
         if(count%2===0){
           iput.focus();
         }
         else{
           iput.blur();
         }
         iput.value=count;  
         if(count>3){
           location.href="http://Nirwana.com";
         }              
         setTimeout(function(){check()},1000);
}   
iput.onblur=function(){count=1}
iput.onfocus=function(){count=1}
check();

Bu başarılı bir taslak FF üzerinde test edildi.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.