Bir kullanıcının bir web sayfasından ayrıldığını tespit etmenin en iyi yolu nedir?


195

Bir kullanıcının bir web sayfasından ayrılıp ayrılmadığını tespit etmenin en iyi yolu nedir?

onunloadJavaScript olay her zaman çalışmıyor (HTTP isteği zaman tarayıcı sonlandırmak için gerekenden daha uzun sürer).

Bir tane oluşturmak muhtemelen mevcut tarayıcılar tarafından engellenir.

Yanıtlar:


219

onbeforeunloadEtkinliği deneyin : Sayfa kaldırılmadan hemen önce tetiklenir. Ayrıca, kullanıcının gerçekten ayrılmak isteyip istemediğini sormanızı da sağlar. Yüklemeden önceki demoya bakın .

Alternatif olarak, ayrıldığında Ajax isteği gönderebilirsiniz .


3
Formun değişip değişmediğini izlediyseniz kullanıcı için iyi olur ve yalnızca yapıldıysa sorulur - bu yüzden can sıkıcı değildir.
adam0101

3
Ayrıca, çeşitli mobil tarayıcıların etkinliğin sonucunu yok saydığını unutmayın (yani kullanıcıdan onay istemezler). Firefox'un aynısını yapmak için about: config'te gizli bir tercihi vardır. Özünde bu, kullanıcının belgenin kaldırılabileceğini her zaman doğruladığı anlamına gelir.
MJB

2
Bu yöntem, kullanıcı sayfayı yenilediğinde veya bir form gönderdiğinde de çağrılır.
Zaytsev Dmitry

@Andreas Petersson, kullanıcı oturumunu bırakmak amacıyla aynı zorluğa sahibim. Bunun projeye ait olup olmadığını kontrol etmek için yazılan URL'yi nasıl yakalayabilirim?
Jcc.Sanabria

21

Mozilla Geliştirici Ağı onbeforeunload'un güzel bir açıklamasına ve örneğine sahiptir .

Sayfanız kirliyse sayfadan ayrılmadan önce kullanıcıyı uyarmak istiyorsanız (ör. Kullanıcı bazı veriler girmişse):

window.addEventListener('beforeunload', function(e) {
  var myPageIsDirty = ...; //you implement this logic...
  if(myPageIsDirty) {
    //following two lines will cause the browser to ask the user if they
    //want to leave. The text of this dialog is controlled by the browser.
    e.preventDefault(); //per the standard
    e.returnValue = ''; //required for Chrome
  }
  //else: user is allowed to leave without a warning dialog
});

10

İşte alternatif bir çözüm oluyor - birçok tarayıcıda gezinme denetimleri (nav çubuğu, sekmeler vb) bulunduğu beri yukarıdaki sayfa içerik alanı, üst yoluyla sayfadan ayrılmadan fare işaretçisi algılar ve görüntüleyebilen bir " Ayrılmadan önce " iletişim. Tamamen göze batmayan ve gerçekten bırakacak eylemi gerçekleştirmeden önce kullanıcıyla etkileşime girmenizi sağlar .

$(document).bind("mouseleave", function(e) {
    if (e.pageY - $(window).scrollTop() <= 1) {    
        $('#BeforeYouLeaveDiv').show();
    }
});

Dezavantajı, elbette kullanıcının aslında ayrılmak istediği bir tahmindir , ancak vakaların büyük çoğunluğunda doğrudur.


Ben bir şey arıyorum, benim kullanıcı için göze batmayan bir şey göstermek istiyorum, sayfamdan ayrılmadan önce, kullanıcı geri dönmek için tıklama önce olayı ateş gerekir, çünkü geri düğmesi üzerinde bir hover olay gibi bir şey arıyorum. En iyi yolun fare bırakma vücut belgesini gerçekten algıladığına ve kullanıcının sayfayla etkileşime girip girmediğini belirlemek için bazı mantık yaptığına inanıyorum.
Leonardo Souza Paiva

8

Bunun için kullanıyorum:

window.onbeforeunload = function (e) {

}

Sayfa kaldırılmadan hemen önce tetiklenir.


1
Opera 12 ve daha eski sürümleri bunu desteklemiyor ... zachleat.com/web/…
Cyrus

Bu aynı çözümü veren önceki iki cevaptan nasıl daha iyi onbeforeunload?
Dan Dascalescu

5

Bu sorunun yanıtlandığını biliyorum, ancak yalnızca bir sayfa yüklendiğinde değil, gerçek BROWSER kapandığında tetiklenecek bir şey istiyorsanız, bu kodu kullanabilirsiniz:

window.onbeforeunload = function (e) {
        if ((window.event.clientY < 0)) {
            //window.localStorage.clear();
            //alert("Y coords: " + window.event.clientY)
        }
};

Örneğimde, yerel depolamayı temizliyorum ve kullanıcıları yalnızca tarayıcı kapalıyken fareler ile uyarıyorum, bu programın içindeki tüm sayfa yüklemelerinde göz ardı edilecektir.


window.event benim için tanımsız
Karl Glaser

Merr Leader örneği yanlış, window.event yalnızca IE'nin eski sürümleri için bir yedek olarak kullanılmalıdır, diğer durumlarda event parametresi ( ebu durumda değişken) kullanılmalıdır: stackoverflow.com/questions/9813445/ …
Sk8erPeter

Yanıldığımı söyleyecek kadar ileri gitmezdim. Örneklerim IE ve Chrome'da benim için iyi çalışıyor. Örneğim, kullanıcının web tarayıcısında X'i (kapat) tıklattığı senaryosuna yönelikti. Ne de en güzel yol belki, ama işe yarıyor.
Merr Lideri

MDN'den: This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. developer.mozilla.org/en-US/docs/Web/API/Window/event
Robin Neal

3

Bunu yapmanın bir (biraz hacky) yolu, sitenizden bir AJAX çağrısı ile sunucu tarafına giden, kullanıcının ayrıldığını belirten bağlantılar, daha sonra kullanıcıyı dış siteye götürmek için aynı javascript bloğunu kullanın. istedim.

Elbette, kullanıcı tarayıcı penceresini kapatırsa veya yeni bir URL yazarsa bu işe yaramaz.

Bunun üstesinden gelmek için, sayfada her birkaç saniyede bir AJAX çağrısı yaparak (kullanıcının ne kadar hızlı ayrıldığını bilmek istediğinize bağlı olarak) Javascript'in setTimeout () yöntemini kullanmanız gerekir.


4
Rapor ana sayfası yaklaşımını kullanırsanız, sayfadaki her bağlantıyı değiştirmenize gerek yoktur.
Vinko Vrsalovic

3

Servis Çalışanları sayesinde , Adam'ın tarayıcıya desteklediği tamamen müşteri tarafında olan bir çözüm uygulamak mümkündür . Sadece kalp atışı isteklerini atlayın:

// The delay should be longer than the heartbeat by a significant enough amount that there won't be false positives
const liveTimeoutDelay = 10000
let liveTimeout = null

global.self.addEventListener('fetch', event => {
  clearTimeout(liveTimeout)
  liveTimeout = setTimeout(() => {
    console.log('User left page')
    // handle page leave
  }, liveTimeoutDelay)
  // Forward any events except for hearbeat events
  if (event.request.url.endsWith('/heartbeat')) {
    event.respondWith(
      new global.Response('Still here')
    )
  }
})

İstemci kodunda bir yerde, bir tane olması gerektiğini mi kastettiniz setInterval(() => fetch('/heartbeat'), 5000)?
Dan Dascalescu

@DanDascalescu Doğru. JS kodu / kalp atışı için bir ağ isteği yapar ve servis çalışanı bunu durdurur.
Jeffrey Sweeney

2

Bazı eşzamansız kodlar yapmanız gerektiğinde (sunucuya kullanıcının şu anda sayfanıza odaklanmadığını belirten bir mesaj göndermek gibi), etkinlik beforeunload, eşzamansız kodun çalıştırılmasına zaman vermez. Zaman uyumsuzluk durumunda visibilitychangeve mouseleaveolaylarının en iyi seçenek olduğunu gördüm . Bu olaylar, kullanıcı sekmeyi değiştirdiğinde veya tarayıcıyı gizlediğinde veya kurslayıcıyı pencere kapsamından çıkardığında tetiklenir.

document.addEventListener('mouseleave', e=>{
     //do some async code
})

document.addEventListener('visibilitychange', e=>{
     if (document.visibilityState === 'visible') {
   //report that user is in focus
    } else {
     //report that user is out of focus
    }  
})


0

Onun değeri için, bu yaptım ve belki de makale eski olsa da başkalarına yardımcı olabilir.

PHP:

session_start();

$_SESSION['ipaddress'] = $_SERVER['REMOTE_ADDR'];

if(isset($_SESSION['userID'])){
    if(!strpos($_SESSION['activeID'], '-')){
        $_SESSION['activeID'] = $_SESSION['userID'].'-'.$_SESSION['activeID'];
    }
}elseif(!isset($_SESSION['activeID'])){
    $_SESSION['activeID'] = time();
}

JS

window.setInterval(function(){
            var userid = '<?php echo $_SESSION['activeID']; ?>';
            var ipaddress = '<?php echo $_SESSION['ipaddress']; ?>';
            var action = 'data';

            $.ajax({
                url:'activeUser.php',
                method:'POST',
                data:{action:action,userid:userid,ipaddress:ipaddress},
                success:function(response){
                     //alert(response);                 
                }
            });
          }, 5000);

ActiveUser.php'ye Ajax çağrısı

if(isset($_POST['action'])){
    if(isset($_POST['userid'])){
        $stamp = time();
        $activeid = $_POST['userid'];
        $ip = $_POST['ipaddress'];

        $query = "SELECT stamp FROM activeusers WHERE activeid = '".$activeid."' LIMIT 1";
        $results = RUNSIMPLEDB($query);

        if($results->num_rows > 0){
            $query = "UPDATE activeusers SET stamp = '$stamp' WHERE activeid = '".$activeid."' AND ip = '$ip' LIMIT 1";
            RUNSIMPLEDB($query);
        }else{
            $query = "INSERT INTO activeusers (activeid,stamp,ip)
                    VALUES ('".$activeid."','$stamp','$ip')";
            RUNSIMPLEDB($query);
        }
    }
}

Veri tabanı:

CREATE TABLE `activeusers` (
  `id` int(11) NOT NULL,
  `activeid` varchar(20) NOT NULL,
  `stamp` int(11) NOT NULL,
  `ip` text
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Temelde js her 5 saniyede bir kullanıcı ve kullanıcıların ip adresini izleyecek bir php dosyasına gönderir. Etkin kullanıcılar, 5 saniye içinde veritabanı zaman damgasını güncelleştiren bir veritabanı kaydıdır. Eski kullanıcılar veritabanına güncellemeyi durdurur. IP adresi sadece bir kullanıcının benzersiz olmasını sağlamak için kullanılır, böylece sitede aynı anda 2 kişi 1 kullanıcı olarak kaydolmaz.

Muhtemelen en verimli çözüm değil ama işi yapıyor.

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.