วิธีที่ดีที่สุดในการตรวจสอบเมื่อผู้ใช้ออกจากหน้าเว็บ?


195

วิธีที่ดีที่สุดในการตรวจสอบว่าผู้ใช้ออกจากหน้าเว็บคืออะไร?

onunloadเหตุการณ์ JavaScript ไม่ทำงานทุกครั้ง (การร้องขอ HTTP ใช้เวลานานกว่าเวลาที่จะต้องยุติการเบราว์เซอร์)

การสร้างอาจจะถูกบล็อกโดยเบราว์เซอร์ปัจจุบัน

คำตอบ:


219

ลองonbeforeunloadเหตุการณ์: มันถูกไล่ออกก่อนที่หน้าจะถูกยกเลิกการโหลด นอกจากนี้ยังอนุญาตให้คุณถามกลับว่าผู้ใช้ต้องการออกจริงหรือไม่ ดูการสาธิตonbeforeunload สาธิต

หรือคุณสามารถส่งคำขอAjaxเมื่อเขาออกไป


3
มันจะเป็นการดีสำหรับผู้ใช้หากคุณติดตามว่าแบบฟอร์มมีการเปลี่ยนแปลงและจะแจ้งให้คุณทราบเท่านั้นหากทำได้ - ดังนั้นจึงไม่น่ารำคาญ
adam0101

3
โปรดทราบว่าเบราว์เซอร์มือถือต่างๆไม่สนใจผลลัพธ์ของเหตุการณ์ (นั่นคือพวกเขาจะไม่ขอให้ผู้ใช้ยืนยัน) Firefox มีการตั้งค่าที่ซ่อนอยู่ใน about: config ให้ทำเช่นเดียวกัน ในสาระสำคัญนี้หมายถึงผู้ใช้ยืนยันเสมอว่าเอกสารอาจถูกยกเลิกการโหลด
MJB

2
โปรดทราบว่าวิธีการนี้จะกระตุ้นเมื่อผู้ใช้รีเฟรชหน้าหรือส่งแบบฟอร์ม
Zaytsev Dmitry

@ Andreas Petersson ฉันมีความท้าทายเดียวกันกับวัตถุประสงค์ในการลบเซสชันผู้ใช้ ฉันจะจับ URL ที่พิมพ์เพื่อตรวจสอบว่าเป็นของโครงการได้อย่างไร
Jcc.Sanabria

21

Mozilla พัฒนาเครือข่ายมีคำอธิบายที่ดีและตัวอย่างของonbeforeunload

หากคุณต้องการเตือนผู้ใช้ก่อนออกจากหน้าหากหน้าเว็บของคุณสกปรก (เช่นหากผู้ใช้ป้อนข้อมูลบางส่วน):

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

ต่อไปนี้เป็นทางเลือกอื่นเนื่องจากในเบราว์เซอร์ส่วนใหญ่การควบคุมการนำทาง (แถบนำทางแท็บ ฯลฯ ) ตั้งอยู่เหนือพื้นที่เนื้อหาของหน้าคุณสามารถตรวจสอบตัวชี้เมาส์ออกจากหน้าผ่านทางด้านบนและแสดง " ก่อนออกจาก " โต้ตอบ มันไม่สร้างความรำคาญอย่างสมบูรณ์และช่วยให้คุณสามารถโต้ตอบกับผู้ใช้ก่อนที่พวกเขาจะออกจากการกระทำจริง

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

ข้อเสียคือแน่นอนว่ามันเป็นเดาว่าผู้ใช้จริงมีความตั้งใจที่จะออก แต่ในส่วนใหญ่ของกรณีมันถูกต้อง


ฉันกำลังมองหาสิ่งที่ต้องการฉันต้องการแสดงสิ่งที่ไม่เป็นการรบกวนผู้ใช้ของฉันก่อนออกจากหน้าของฉันฉันกำลังมองหาบางสิ่งบางอย่างเช่นเหตุการณ์โฮเวอร์ที่ปุ่มย้อนกลับเพราะฉันต้องการเริ่มเหตุการณ์ก่อนที่ผู้ใช้จะคลิกเพื่อย้อนกลับ ฉันเชื่อว่าวิธีที่ดีที่สุดคือการตรวจสอบเอกสารจากเม้าส์และทำตามตรรกะเพื่อตัดสินว่าผู้ใช้โต้ตอบกับหน้าเว็บหรือไม่
Leonardo Souza Paiva

8

สำหรับสิ่งนี้ฉันใช้:

window.onbeforeunload = function (e) {

}

มันถูกไล่ออกก่อนที่จะยกเลิกการโหลดหน้าเว็บ


1
Opera 12 และรุ่นที่เก่ากว่านี้ไม่รองรับ ... zachleat.com/web/…
Cyrus

นี่เป็นวิธีที่ดีกว่าสองคำตอบก่อนหน้านี้ที่ให้ทางออกเดียวกันได้onbeforeunloadอย่างไร
Dan Dascalescu

5

ฉันรู้ว่าคำถามนี้ได้รับการตอบแล้ว แต่ในกรณีที่คุณต้องการให้สิ่งที่จะเรียกเมื่อเบราว์เซอร์ที่แท้จริงถูกปิดและไม่เพียงเมื่อ pageload เกิดขึ้นคุณสามารถใช้รหัสนี้:

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

ในตัวอย่างของฉันฉันกำลังเคลียร์ที่เก็บข้อมูลโลคัลและแจ้งเตือนผู้ใช้ด้วย mouses y coords เฉพาะเมื่อปิดเบราว์เซอร์เท่านั้นสิ่งนี้จะถูกละเว้นในทุกหน้าโหลดจากภายในโปรแกรม


window.event ไม่ได้กำหนดไว้สำหรับฉัน
Karl Glaser

ตัวอย่างของผู้นำ Merr ไม่ถูกต้องควรใช้ window.event เป็นทางเลือกสำหรับ IE เวอร์ชันเก่าในกรณีอื่น ๆeควรใช้พารามิเตอร์เหตุการณ์ ( ตัวแปรในกรณีนี้): stackoverflow.com/questions/9813445/ …
Sk8erPeter

จะไม่ไปไกลเท่าที่จะบอกว่าฉันผิด ตัวอย่างของฉันทำงานได้ดีสำหรับฉันใน IE และ Chrome ตัวอย่างของฉันสำหรับสถานการณ์ที่ผู้ใช้คลิก X (ปิด) บนเว็บเบราว์เซอร์ หรือวิธีที่สวยที่สุด แต่ก็ใช้งานได้
ผู้นำ Merr

จาก 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

วิธีหนึ่ง (แฮ็คเล็กน้อย) เพื่อแทนที่และลิงก์ที่นำไปจากไซต์ของคุณด้วยการโทร AJAX ไปยังฝั่งเซิร์ฟเวอร์เพื่อระบุว่าผู้ใช้กำลังออกจากนั้นใช้บล็อกจาวาสคริปต์เดียวกันเพื่อนำผู้ใช้ไปยังไซต์ภายนอกที่พวกเขา ได้รับการร้องขอ

แน่นอนว่าสิ่งนี้จะไม่ทำงานหากผู้ใช้ปิดหน้าต่างเบราว์เซอร์หรือประเภทใน URL ใหม่

ในการหลีกเลี่ยงสิ่งนั้นคุณอาจต้องใช้ setTimeout () ของ Javascript บนหน้าเว็บทำการโทร AJAX ทุกสองสามวินาที (ขึ้นอยู่กับความเร็วที่คุณต้องการทราบหากผู้ใช้ออกไป)


4
หากคุณใช้วิธีการรายงานแบบโฮมคุณไม่จำเป็นต้องแก้ไขทุกลิงก์ในหน้า
Vinko Vrsalovic

3

ต้องขอบคุณService Workersมันเป็นไปได้ที่จะใช้วิธีการแก้ปัญหาที่คล้ายกับอดัมล้วนๆบนฝั่งไคลเอ็นต์โดยให้เบราว์เซอร์รองรับ หลีกเลี่ยงการร้องขอการเต้นของหัวใจ:

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

คุณหมายถึงบางที่ในรหัสลูกค้าจำเป็นต้องมีsetInterval(() => fetch('/heartbeat'), 5000)?
Dan Dascalescu

@DanDascalescu ถูกต้อง รหัส JS ทำให้คำขอเครือข่ายไปที่ / heartbeat และผู้ให้บริการดักจับมัน
Jeffrey Sweeney

2

ในกรณีที่คุณต้องทำโค้ดแบบอะซิงโครนัส (เช่นการส่งข้อความไปยังเซิร์ฟเวอร์ที่ผู้ใช้ไม่ได้มุ่งเน้นไปที่หน้าของคุณตอนนี้) เหตุการณ์beforeunloadจะไม่ให้เวลากับรหัส async เพื่อให้ทำงาน ในกรณีของ async ฉันพบว่าvisibilitychangeและmouseleaveเหตุการณ์เป็นตัวเลือกที่ดีที่สุด เหตุการณ์เหล่านี้เริ่มต้นขึ้นเมื่อผู้ใช้เปลี่ยนแท็บหรือซ่อนเบราว์เซอร์หรือนำเคอร์เซอร์ออกจากขอบเขตหน้าต่าง

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

สำหรับสิ่งที่คุ้มค่านี่คือสิ่งที่ฉันทำและอาจช่วยคนอื่นได้แม้ว่าบทความจะเก่า

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

โทร Ajax ไปยัง 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);
        }
    }
}

ฐานข้อมูล:

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;

โดยทั่วไปทุกๆ 5 วินาที js จะโพสต์ไปยังไฟล์ php ที่จะติดตามผู้ใช้และที่อยู่ ip ของผู้ใช้ ผู้ใช้ที่ใช้งานอยู่เป็นเพียงบันทึกฐานข้อมูลที่มีการปรับปรุงการประทับเวลาของฐานข้อมูลภายใน 5 วินาที ผู้ใช้เก่าหยุดการอัปเดตเป็นฐานข้อมูล ที่อยู่ IP นั้นใช้เพื่อให้แน่ใจว่าผู้ใช้นั้นไม่เหมือนใครดังนั้น 2 คนบนเว็บไซต์ในเวลาเดียวกันไม่ได้ลงทะเบียนเป็น 1 ผู้ใช้

อาจไม่ใช่โซลูชันที่มีประสิทธิภาพที่สุด แต่ทำงานได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.