ユーザーがブラウザの戻るボタンを押したかどうかをどうやって確実に検出しますか?
#URL
システムを使用して、1ページのWebアプリケーション内でページ内の戻るボタンをどのように使用するように強制しますか?
一体何のブラウザバックボタンが独自のイベントを起こさないのですか??
(注:Sharkyのフィードバックに従って、バックスペースを検出するためのコードを含めました)
それで、私はこれらの質問をSOで頻繁に見ました、そして、最近私自身が戻るボタン機能性を制御する問題に出くわしました。自分のアプリケーションに最適な解決策(Hash Navigation付きの単一ページ)を探して数日後、戻るボタンを検出するためのシンプルでクロスブラウザの、ライブラリのないシステムを思いつきました。
ほとんどの人は以下のものを使うことを勧めます。
window.onhashchange = function() {
//blah blah blah
}
ただし、この関数は、ユーザーがロケーションハッシュを変更するページ内要素を使用したときにも呼び出されます。ユーザーがクリックしてページが前後に移動したときの最高のユーザーエクスペリエンスではありません。
私のシステムの概要を説明するために、私のユーザーがインタフェースを移動するにつれて、以前のハッシュで配列を埋めます。それはこのようになります:
function updateHistory(curr) {
window.location.lasthash.Push(window.location.hash);
window.location.hash = curr;
}
かなり簡単です。私はこれを、クロスブラウザサポートと、より古いブラウザのサポートを確実にするために行います。単純に関数に新しいハッシュを渡すと、それはあなたのためにそれを保存してからハッシュを変更します(それはブラウザの履歴に入れられます)。
また、lasthash
配列を使用してページ間でユーザーを移動するページ内戻るボタンも利用します。それはこのように見えます:
function goBack() {
window.location.hash = window.location.lasthash[window.location.lasthash.length-1];
//blah blah blah
window.location.lasthash.pop();
}
そのため、ユーザーは最後のハッシュに戻り、その最後のハッシュを配列から削除します(今は進むボタンがありません)。
そう。ユーザーが自分のページ内戻るボタンまたはブラウザボタンを使用したかどうかをどのように検出しますか?
最初はwindow.onbeforeunload
を見ましたが、役に立ちません - ユーザーがページを変更しようとしている場合にのみ呼び出されます。これは、ハッシュナビゲーションを使用する単一ページのアプリケーションでは起こりません。
それで、もう少し掘り下げた後、私はフラグ変数を設定しようとするための勧告を見ました。私の場合のこれの問題は、私がそれを設定しようとすることですが、すべてが非同期であるので、ハッシュ変更のifステートメントに間に合うように設定されるとは限らないでしょう。 .onMouseDown
は必ずしもクリックで呼び出されるわけではなく、それをonclickに追加してもそれほど速くトリガーされることはありません。
document
とwindow
の違いを調べ始めたのはこのときです。私の最後の解決策はdocument.onmouseover
を使ってフラグを設定し、document.onmouseleave
を使ってそれを無効にすることでした。
何が起こるかというと、ユーザーのマウスがドキュメント領域の中にある間(読み取り:レンダリングされたページだがブラウザフレームは除く)、私のブール値はtrue
に設定されています。マウスがドキュメント領域を離れるとすぐに、ブール値はfalse
に反転します。
このようにして、私のwindow.onhashchange
を次のように変更することができます。
window.onhashchange = function() {
if (window.innerDocClick) {
window.innerDocClick = false;
} else {
if (window.location.hash != '#undefined') {
goBack();
} else {
history.pushState("", document.title, window.location.pathname);
location.reload();
}
}
}
#undefined
のチェックに気づくでしょう。これは私の配列に利用可能な履歴がない場合はundefined
を返すからです。私はこれを使用して、window.onbeforeunload
イベントを使用してユーザーが退席するかどうかをユーザーに確認します。
つまり、要するに、履歴を保存するのに必ずしもページ内の戻るボタンや配列を使用しているわけではない人々のためのものです。
document.onmouseover = function() {
//User's mouse is inside the page.
window.innerDocClick = true;
}
document.onmouseleave = function() {
//User's mouse has left the page.
window.innerDocClick = false;
}
window.onhashchange = function() {
if (window.innerDocClick) {
//Your own in-page mechanism triggered the hash change
} else {
//Browser back button was clicked
}
}
そして、あなたはそれを持っています。ハッシュナビゲーションに関して、戻るボタンの使用とページ内要素を検出するための簡単な3部構成の方法。
編集:
ユーザーがバックイベントを使用してバックイベントをトリガーしないようにするために、次のものも含めることができます(@thetoolman on this question に感謝します)。
$(function(){
/*
* this swallows backspace keys on any non-input element.
* stops backspace -> back
*/
var rx = /INPUT|SELECT|TEXTAREA/i;
$(document).bind("keydown keypress", function(e){
if( e.which == 8 ){ // 8 == backspace
if(!rx.test(e.target.tagName) || e.target.disabled || e.target.readOnly ){
e.preventDefault();
}
}
});
});
popstate
event handlerを試すことができます。例えば:
window.addEventListener('popstate', function(event) {
// The popstate event is fired each time when the current history entry changes.
var r = confirm("You pressed a Back button! Are you sure?!");
if (r == true) {
// Call Back button programmatically as per user confirmation.
history.back();
// Uncomment below line to redirect to the previous page instead.
// window.location = document.referrer // Note: IE11 is not supporting this.
} else {
// Stay on the current page.
history.pushState(null, null, window.location.pathname);
}
history.pushState(null, null, window.location.pathname);
}, false);
注:最良の結果を得るには、他の予期しない問題を回避するためにロジックを実装する特定のページにのみこのコードをロードしてください。
Popstateイベントは、現在の履歴エントリが変更されるたびに発生します(ユーザーが新しい状態に移動する)。これは、ユーザーがブラウザの[戻る]/[進む]ボタンをクリックしたとき、またはhistory.back()
、history.forward()
、history.go()
メソッドがプログラム的に呼び出されたときに発生します。
event.state
はイベントのプロパティで、履歴状態オブジェクトと同じです。
JQuery構文の場合は、それをラップします(ドキュメントの準備ができた後にリスナーを追加するため)。
(function($) {
// Above code here.
})(jQuery);
シングルページアプリとHTML5 pushState pageの例も参照してください。
<script>
// jQuery
$(window).on('popstate', function (e) {
var state = e.originalEvent.state;
if (state !== null) {
//load content with ajax
}
});
// Vanilla javascript
window.addEventListener('popstate', function (e) {
var state = e.state;
if (state !== null) {
//load content with ajax
}
});
</script>
これはChrome 5以降、Firefox 4以降、IE10以降、Safari 6以降、Opera 11.5以降などと互換性があります。
私は長い間この要件に苦労してきましたが、それを実装するために上記の解決策をいくつか採用しました。しかし、私は観察につまずいた、そしてそれはChrome、FirefoxとSafariブラウザ+ AndroidとiPhoneの向こう側に働くように思われる
ページロード時:
window.history.pushState({page: 1}, "", "");
window.onpopstate = function(event) {
// "event" object seems to contain value only when the back button is clicked
// and if the pop state event fires due to clicks on a button
// or a link it comes up as "undefined"
if(event){
// Code to handle back button or prevent from navigation
}
else{
// Continue user action through link or button
}
}
これが役立つかどうか私に知らせてください。何かが足りない場合は、理解していただきます。
Javascriptでは、ナビゲーションタイプ2
はブラウザの戻るボタンまたは進むボタンがクリックされたことを意味し、ブラウザは実際にキャッシュからコンテンツを取得しています。
if(performance.navigation.type == 2)
{
//Do your code here
}
ブラウザ: https://jsfiddle.net/Limitlessisa/axt1Lqoz/ /
モバイルコントロールの場合: https://jsfiddle.net/Limitlessisa/axt1Lqoz/show/
$(document).ready(function() {
$('body').on('click touch', '#share', function(e) {
$('.share').fadeIn();
});
});
// geri butonunu yakalama
window.onhashchange = function(e) {
var oldURL = e.oldURL.split('#')[1];
var newURL = e.newURL.split('#')[1];
if (oldURL == 'share') {
$('.share').fadeOut();
e.preventDefault();
return false;
}
//console.log('old:'+oldURL+' new:'+newURL);
}
.share{position:fixed; display:none; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,.8); color:white; padding:20px;
<!DOCTYPE html>
<html>
<head>
<title>Back Button Example</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body style="text-align:center; padding:0;">
<a href="#share" id="share">Share</a>
<div class="share" style="">
<h1>Test Page</h1>
<p> Back button press please for control.</p>
</div>
</body>
</html>
これは間違いなく動作します(戻るボタンのクリックを検出するため)
$(window).on('popstate', function(event) {
alert("pop");
});
これが私の考えです。 URLが変更されても、検出されたdocument
内にクリックがない場合は、ブラウザが戻る(yes、またはforward)と仮定しています。 Ajaxを介してコンテンツをロードするページでこれを機能させるために、ユーザーのクリックは2秒後にリセットされます。
(function(window, $) {
var anyClick, consoleLog, debug, delay;
delay = function(sec, func) {
return setTimeout(func, sec * 1000);
};
debug = true;
anyClick = false;
consoleLog = function(type, message) {
if (debug) {
return console[type](message);
}
};
$(window.document).click(function() {
anyClick = true;
consoleLog("info", "clicked");
return delay(2, function() {
consoleLog("info", "reset click state");
return anyClick = false;
});
});
return window.addEventListener("popstate", function(e) {
if (anyClick !== true) {
consoleLog("info", "Back clicked");
return window.dataLayer.Push({
event: 'analyticsEvent',
eventCategory: 'test',
eventAction: 'test'
});
}
});
})(window, jQuery);
これを見なさい:
history.pushState(null, null, location.href);
window.onpopstate = function () {
history.go(1);
};
それはうまくいきます...
質問に答えるために、正しい答えがすでにあります。新しいJavaScript API PerformanceNavigationTiming に言及したいのですが、廃止された performance.navigation に取って代わります。
ユーザーが戻るまたは進むボタンを使用してページに到達した場合、次のコードはコンソール「back_forward」にログインします。 プロジェクトで使用する前に互換性テーブルを確認してください。
var perfEntries = performance.getEntriesByType("navigation");
for (var i = 0; i < perfEntries.length; i++) {
console.log(perfEntries[i].type);
}
誰かがブラウザの戻るボタンでページに戻ったときに呼び出されるイベントリスナーを追加し、そのイベントでページをリロードするだけで、このタスクを以下のトリックで行いました。お役に立てば幸いです。
window.addEventListener("pageshow", function(event) {
var historyTraversal = event.persisted || (typeof window.performance !=
"undefined" && window.performance.navigation.type === 2);
if (historyTraversal) {
// Handle page restore.
window.location.reload();
}
});
このコードをページの下部に追加しました。
<input style="display:none" id="__pageLoaded" value=""/>
$(document).ready(function () {
if ($("#__pageLoaded").val() != 1) {
$("#__pageLoaded").val(1);
} else {
shared.isBackLoad = true;
$("#__pageLoaded").val(1);
// Call any function that handles your back event
}
});
上記のコードは私のために働きました。モバイルブラウザでは、ユーザーが[戻る]ボタンをクリックしたときに、前回の訪問時と同じようにページの状態を復元する必要がありました。
私はこのスレッドの中のいくつかの答えと他のものをIEとChrome/Edgeで動かすために使うことができました。 history.pushState 私にとってIE11ではサポートされていませんでした。
if (history.pushState) {
//Chrome and modern browsers
history.pushState(null, document.title, location.href);
window.addEventListener('popstate', function (event) {
history.pushState(null, document.title, location.href);
});
}
else {
//IE
history.forward();
}
Document.mouseoverはIEおよびFireFoxでは機能しません。しかし私はこれを試してみました:
$(document).ready(function () {
setInterval(function () {
var $sample = $("body");
if ($sample.is(":hover")) {
window.innerDocClick = true;
} else {
window.innerDocClick = false;
}
});
});
window.onhashchange = function () {
if (window.innerDocClick) {
//Your own in-page mechanism triggered the hash change
} else {
//Browser back or forward button was pressed
}
};
これはChromeおよびIEでは機能し、FireFoxでは機能しません。まだFireFoxを正しくするために働いています。ブラウザの戻る/進むボタンのクリックを検出するための簡単な方法は、特にJQueryではなくAngularJSや普通のJavascriptでも構いません。
if (window.performance && window.performance.navigation.type == window.performance.navigation.TYPE_BACK_FORWARD) {
alert('hello world');
}
これは私のために働いた唯一の解決策です(それはワンページのウェブサイトではありません)。 Chrome、Firefox、Safariで動作しています。
私はそれがhashchange
(それがスワイプ、クリックまたはホイールであること)を引き起こしたオリジナルの出来事を追跡することによってそれを解決したので、その出来事は単純なページ上のランディングと間違われないように、そして追加のフラグを使う私の各イベントバインディングで。ブラウザは、戻るボタンを押したときに再びフラグをfalse
に設定しません。
var evt = null,
canGoBackToThePast = true;
$('#next-slide').on('click touch', function(e) {
evt = e;
canGobackToThePast = false;
// your logic (remember to set the 'canGoBackToThePast' flag back to 'true' at the end of it)
}