ユーザーがWebページを離れたときに検出する最良の方法は?


195

ユーザーがWebページを離れたかどうかを検出する最良の方法は何ですか?

onunloadJavaScriptイベントは毎回動作しません(HTTPリクエストは時間がブラウザを終了するのに必要なよりも時間がかかります)。

1つを作成すると、現在のブラウザによってブロックされる可能性があります。

回答:


219

onbeforeunloadイベントを試してください:ページがアンロードされる直前に発生します。また、ユーザーが本当に離れたいかどうかを尋ねることもできます。デモを見るonbeforeunload Demo

または、彼が去ったときにAjaxリクエストを送信することもできます。


3
フォームが変更されたかどうかを追跡し、変更された場合にのみプロンプトを表示すると、ユーザーにとって便利です。
adam0101

3
また、さまざまなモバイルブラウザはイベントの結果を無視します(つまり、ユーザーに確認を求めません)。Firefoxには、about:configに同じことをする隠し設定があります。つまり、これは、ユーザーがドキュメントがアンロードされる可能性があることを常に確認することを意味します。
MJB 2015年

2
このメソッドは、ユーザーがページを更新したり、フォームを送信したりしたときにも呼び出されることに注意してください。
Zaytsev Dmitry

@Andreas Petersson、私はユーザーセッションを削除することを目的として同じ課題を抱えています。入力したURLをキャプチャして、プロジェクトに属しているかどうかを確認するにはどうすればよいですか?
Jcc.Sanabria

21

Mozilla Developer Networkには、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
オペラ12と古いバージョンがこれをサポートしていません... zachleat.com/web/...
サイラス

これは、同じ解決策を与える前の2つの回答よりも優れてい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は私には定義されていません
Karl Glaser

Merr Leaderの例は間違っています。window.eventは、たとえば古いバージョンのIEのフォールバックとしてのみ使用する必要があります。それ以外の場合は、イベントパラメータ(eこの場合は変数)を使用する必要があります: stackoverflow.com/questions/9813445/ …
Sk8erPeter

私が間違っていると言うほどには行きません。私の例は、IEとChromeでうまく機能します。私の例は、ユーザーがWebブラウザーでX(閉じる)をクリックするシナリオです。最もきれいな方法でもないかもしれませんが、それはうまくいきます。
Merリーダー、

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

これを行う(少しハッキーな)方法の1つは、サイトから離れるリンクをサーバー側へのAJAX呼び出しで置き換え、ユーザーが離れていることを示し、同じJavaScriptブロックを使用してユーザーを外部サイトに連れて行くことですリクエストしました。

もちろん、これは、ユーザーがブラウザウィンドウを閉じるか、新しいURLを入力するだけでは機能しません。

これを回避するには、ページでJavaScriptのsetTimeout()を使用し、数秒ごとにAJAX呼び出しを行う必要があります(ユーザーが離れたかどうかを知りたい速さによって異なります)。


4
レポートホームアプローチを使用する場合、ページ内のすべてのリンクを変更する必要はありません。
Vinko Vrsalovic 2008

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

2

非同期コードを実行する必要がある場合(ユーザーが現在ページにフォーカスしていないというメッセージをサーバーに送信するなど)、イベントbeforeunloadは非同期コードの実行に時間を与えません。非同期の場合、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);

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.