사용자가 웹 페이지를 떠날 때 감지하는 가장 좋은 방법은 무엇입니까?


195

사용자가 웹 페이지를 떠 났는지 감지하는 가장 좋은 방법은 무엇입니까?

onunload자바 스크립트 이벤트 때마다 작동하지 않습니다 (HTTP 요청은 시간이 브라우저를 종료하는 데 필요한보다 오래 걸립니다).

하나를 생성하면 현재 브라우저에 의해 차단 될 수 있습니다.

답변:


219

onbeforeunload이벤트를 보십시오 : 페이지가 언로드되기 직전에 시작됩니다. 또한 사용자가 실제로 떠나기를 원하는지 다시 물어볼 수 있습니다. 데모 onbeforeunload 데모를 참조하십시오 .

또는 Ajax가 떠날 때 요청을 보낼 수 있습니다 .


3
양식이 변경되었는지 추적하고 확인했을 때만 프롬프트하면 사용자에게 좋을 것이므로 성 가시지 않습니다.
adam0101

3
또한 다양한 모바일 브라우저는 이벤트 결과를 무시합니다 (즉, 사용자에게 확인을 요청하지 않음). Firefox는 about : config에서 숨겨진 환경 설정을 사용하여 동일한 작업을 수행합니다. 본질적으로 이것은 사용자가 항상 문서가 언로드 될 수 있음을 확인하는 것을 의미합니다.
MJB

2
이 방법은 사용자가 페이지를 새로 고치거나 양식을 제출할 때도 발생합니다.
Zaytsev Dmitry

@Andreas Petersson, 나는 사용자 세션을 삭제한다는 목표와 같은 도전을했습니다. 입력 한 URL을 캡처하여 프로젝트에 속하는지 어떻게 확인할 수 있습니까?
Jcc.Sanabria 2018 년

21

모질라 개발자 네트워크는 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

이 질문에 대한 답변은 알고 있지만 페이지로드가 발생할 때뿐만 아니라 실제 브라우저가 닫힐 때만 트리거하려는 것이 있으면이 코드를 사용할 수 있습니다.

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

내 예에서는 브라우저가 닫혀있을 때만 로컬 저장소를 지우고 마우스와 y 좌표로 사용자에게 경고합니다. 프로그램 내 모든 페이지로드에서 무시됩니다.


window.event는 저에게 정의되어 있지 않습니다
칼 글레이저에게

Merr Leader의 예제가 잘못되었습니다. window.event는 이전 버전의 IE에 대한 폴백으로 만 사용해야하며, 다른 경우에는 이벤트 매개 변수 ( e이 경우 변수)를 사용해야합니다. stackoverflow.com/questions/9813445/ …
Sk8erPeter

내가 틀렸다고 말하지 않을 것입니다. 내 예제는 IE와 Chrome에서 잘 작동합니다. 내 예제는 사용자가 웹 브라우저에서 X (닫기)를 클릭하는 시나리오에 대한 것입니다. 가장 예쁜 방법은 아니지만 작동합니다.
Merr Leader

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 호출로 사이트에서 벗어나는 링크를 대체하고 링크하는 것입니다. 사용자가 떠나고 있음을 나타내는 동일한 Javascript 블록을 사용하여 사용자를 외부 사이트로 이동시킵니다. 요청했습니다.

물론 사용자가 브라우저 창을 닫거나 새 URL을 입력하면 작동하지 않습니다.

이 문제를 해결하려면 페이지에서 Javascript의 setTimeout ()을 사용하여 몇 초마다 AJAX 호출을 수행해야합니다 (사용자가 떠 났는지 얼마나 빨리 알고 있는지에 따라 다름).


4
보고서 홈 접근 방식을 사용하는 경우 페이지의 모든 링크를 수정할 필요가 없습니다.
Vinko Vrsalovic

3

Service Workers 덕분에 브라우저가 지원하는 경우 클라이언트 측에서 Adam 과 완전히 유사한 솔루션을 구현할 수 있습니다. 하트 비트 요청을 피하십시오.

// 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 14:01에

2

사용자가 현재 페이지에 집중하지 않은 메시지를 서버에 보내는 것과 같이 일부 비동기 코드를 수행해야하는 경우 이벤트 beforeunload는 비동기 코드를 실행할 시간을 제공하지 않습니다. 비동기의 경우 visibilitychangemouseleave이벤트가 최상의 옵션 이라는 것을 알았습니다 . 이 이벤트는 사용자가 탭을 변경하거나 브라우저를 숨기거나 창 범위에서 코스를 가져갈 때 발생합니다.

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

activeUser.php에 대한 Ajax 호출

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는 사용자와 사용자의 IP 주소를 추적하는 PHP 파일에 게시합니다. 활성 사용자는 단순히 5 초 내에 데이터베이스 타임 스탬프가 업데이트 된 데이터베이스 레코드입니다. 이전 사용자는 데이터베이스 업데이트를 중지합니다. IP 주소는 사용자가 고유한지 확인하기 위해 사용되므로 사이트에서 2 명이 동시에 1 명의 사용자로 등록하지 않습니다.

아마도 가장 효율적인 솔루션은 아니지만 일을합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.