Cara terbaik untuk mendeteksi ketika pengguna meninggalkan halaman web?

195

Apa cara terbaik untuk mendeteksi jika pengguna meninggalkan halaman web?

Acara onunloadJavaScript tidak berfungsi setiap waktu (permintaan HTTP membutuhkan waktu lebih lama dari waktu yang diperlukan untuk menghentikan browser).

Membuat satu mungkin akan diblokir oleh browser saat ini.

ANaimi
sumber

Jawaban:

219

Coba onbeforeunloadacara: Ini dipecat tepat sebelum halaman diturunkan. Ini juga memungkinkan Anda untuk bertanya kembali apakah pengguna benar-benar ingin pergi. Lihat demo sebelumMuat Demo .

Atau, Anda dapat mengirim permintaan Ajax ketika dia pergi.

Andreas Petersson
sumber
3
Akan lebih baik bagi pengguna jika Anda melacak jika formulir berubah dan hanya meminta jika itu terjadi - jadi itu tidak mengganggu.
adam0101
3
Perhatikan juga bahwa berbagai browser seluler mengabaikan hasil acara (yaitu, mereka tidak meminta konfirmasi kepada pengguna). Firefox memiliki preferensi tersembunyi di about: config untuk melakukan hal yang sama. Intinya ini berarti pengguna selalu mengonfirmasi bahwa dokumen mungkin dibongkar.
MJB
2
Perhatikan bahwa metode ini juga membangkitkan ketika pengguna me-refresh halaman atau mengirimkan formulir.
Zaytsev Dmitry
@Andreas Petersson, saya memiliki tantangan yang sama dengan tujuan untuk menghentikan sesi pengguna. Bagaimana saya bisa menangkap url yang diketik untuk memeriksa apakah itu milik proyek?
Jcc.Sanabria
21

Jaringan Pengembang Mozilla memiliki deskripsi dan contoh yang bagus tentang onbeforeunload .

Jika Anda ingin memperingatkan pengguna sebelum meninggalkan halaman jika halaman Anda kotor (yaitu jika pengguna telah memasukkan beberapa data):

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
});
DuckMaestro
sumber
10

Inilah solusi alternatif - karena di sebagian besar browser kontrol navigasi (bilah navigasi, tab, dll.) Terletak di atas area konten halaman, Anda dapat mendeteksi penunjuk mouse yang meninggalkan halaman melalui bagian atas dan menampilkan " sebelum Anda pergi " dialog. Ini benar-benar tidak mengganggu dan memungkinkan Anda untuk berinteraksi dengan pengguna sebelum mereka benar-benar melakukan tindakan untuk pergi.

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

Kelemahannya adalah tentu saja dugaan bahwa pengguna benar-benar berniat untuk pergi, tetapi dalam sebagian besar kasus itu benar.

rustyx
sumber
saya melihat sesuatu seperti, saya ingin menunjukkan sesuatu yang tidak mengganggu kepada pengguna saya, sebelum meninggalkan halaman saya, saya melihat sesuatu seperti acara hover di tombol kembali, karena saya perlu memecat acara sebelum pengguna mengklik untuk kembali. Saya percaya bahwa cara terbaik adalah benar-benar mendeteksi dokumen cuti mouse tubuh, dan melakukan beberapa logika untuk menentukan apakah pengguna berinteraksi dengan halaman.
Leonardo Souza Paiva
8

Untuk ini saya menggunakan:

window.onbeforeunload = function (e) {

}

Itu dipecat tepat sebelum halaman diturunkan.

suhailvs
sumber
1
Opera 12 dan versi yang lebih lama tidak mendukung ini ... zachleat.com/web/…
Cyrus
Bagaimana ini lebih baik dari dua jawaban sebelumnya yang memberikan solusi yang sama onbeforeunload,?
Dan Dascalescu
5

Saya tahu pertanyaan ini telah dijawab, tetapi jika Anda hanya ingin sesuatu untuk dipicu ketika BROWSER yang sebenarnya ditutup, dan bukan hanya ketika terjadi pageload, Anda dapat menggunakan kode ini:

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

Dalam contoh saya, saya mengosongkan penyimpanan lokal dan memberi tahu pengguna dengan mouse y coords, hanya ketika browser ditutup, ini akan diabaikan pada semua pemuatan halaman dari dalam program.

Pemimpin Merr
sumber
window.event tidak ditentukan untuk saya
Karl Glaser
Contoh Merr Leader salah, window.event seharusnya hanya digunakan sebagai fallback misalnya untuk versi IE yang lebih lama, dalam kasus lain, parameter event ( evariabel dalam kasus ini) harus digunakan: stackoverflow.com/questions/9813445/ …
Sk8erPeter
Tidak akan mengatakan bahwa saya salah. Contoh saya berfungsi baik untuk saya di IE dan Chrome. Contoh saya adalah untuk skenario bahwa pengguna mengklik X (tutup) di browser web. Atau cara tercantik mungkin, tetapi tidak berhasil.
Merr Leader
Dari MDN: 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

Salah satu (sedikit hacky) cara untuk melakukannya adalah mengganti dan tautan yang mengarah keluar dari situs Anda dengan panggilan AJAX ke sisi server, menunjukkan pengguna pergi, kemudian menggunakan blok javascript yang sama untuk membawa pengguna ke situs eksternal yang mereka sudah diminta.

Tentu saja ini tidak akan berhasil jika pengguna cukup menutup jendela browser atau mengetikkan URL baru.

Untuk menyiasatinya, Anda mungkin perlu menggunakan setTimeout () Javascript pada halaman, membuat panggilan AJAX setiap beberapa detik (tergantung seberapa cepat Anda ingin tahu apakah pengguna telah pergi).

Steve M
sumber
4
Jika Anda menggunakan pendekatan beranda laporan, Anda tidak perlu mengubah setiap tautan di halaman.
Vinko Vrsalovic
3

Berkat Pekerja Servis , dimungkinkan untuk mengimplementasikan solusi yang mirip dengan Adam murni di sisi klien, asalkan browser mendukungnya. Hanya menghindari permintaan detak jantung:

// 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')
    )
  }
})
Jeffrey Sweeney
sumber
Apakah maksud Anda di suatu tempat dalam kode klien, harus ada setInterval(() => fetch('/heartbeat'), 5000)?
Dan Dascalescu
@DanDascalescu Benar. Kode JS membuat permintaan jaringan ke / detak jantung, dan pekerja layanan menyadapnya.
Jeffrey Sweeney
2

Jika Anda perlu melakukan beberapa kode asinkron (seperti mengirim pesan ke server bahwa pengguna tidak fokus pada halaman Anda saat ini), acara beforeunloadtidak akan memberikan waktu untuk menjalankan kode async. Dalam kasus async saya menemukan bahwa visibilitychangedan mouseleaveperistiwa adalah opsi terbaik. Peristiwa ini memanas saat pengguna mengubah tab, atau menyembunyikan browser, atau mengeluarkan courser dari lingkup jendela.

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
    }  
})

Tal Yaron
sumber
0

Untuk apa nilainya, ini adalah apa yang saya lakukan dan mungkin dapat membantu orang lain walaupun artikel itu sudah tua.

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);

Panggilan Ajax ke activeUser.php

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);
        }
    }
}

Basis data:

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;

Pada dasarnya setiap 5 detik js akan memposting ke file php yang akan melacak pengguna dan alamat ip pengguna. Pengguna aktif hanyalah catatan basis data yang memiliki pembaruan ke cap waktu basis data dalam waktu 5 detik. Pengguna lama berhenti memperbarui ke database. Alamat ip digunakan hanya untuk memastikan bahwa pengguna unik sehingga 2 orang di situs pada saat yang sama tidak mendaftar sebagai 1 pengguna.

Mungkin bukan solusi yang paling efisien tetapi itu berhasil.

Adam
sumber