คุณจะตรวจสอบอย่างชัดเจนว่าผู้ใช้กดปุ่มย้อนกลับในเบราว์เซอร์อย่างไรหรือไม่?
คุณบังคับใช้ปุ่มย้อนกลับในหน้าภายในเว็บแอปพลิเคชันหน้าเดียวโดยใช้#URL
ระบบได้อย่างไร
ทำไมบนโลกไม่เบราว์เซอร์ปุ่มย้อนกลับยิงเหตุการณ์ของตัวเอง!?
คุณจะตรวจสอบอย่างชัดเจนว่าผู้ใช้กดปุ่มย้อนกลับในเบราว์เซอร์อย่างไรหรือไม่?
คุณบังคับใช้ปุ่มย้อนกลับในหน้าภายในเว็บแอปพลิเคชันหน้าเดียวโดยใช้#URL
ระบบได้อย่างไร
ทำไมบนโลกไม่เบราว์เซอร์ปุ่มย้อนกลับยิงเหตุการณ์ของตัวเอง!?
คำตอบ:
(หมายเหตุ: ตามข้อเสนอแนะของ Sharky ฉันได้รวมรหัสเพื่อตรวจหา backspaces)
ดังนั้นฉันจึงเห็นคำถามเหล่านี้บ่อยๆเกี่ยวกับ SO และเมื่อเร็ว ๆ นี้พบปัญหาในการควบคุมการทำงานของปุ่มย้อนกลับด้วยตัวเอง หลังจากสองสามวันของการค้นหาทางออกที่ดีที่สุดสำหรับแอปพลิเคชันของฉัน (Single-Page ด้วยการนำทางแฮช) ฉันมาพร้อมกับเบราว์เซอร์ที่เรียบง่ายและระบบที่ไม่มีไลบรารีเพื่อตรวจหาปุ่มย้อนกลับ
คนส่วนใหญ่แนะนำให้ใช้:
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
}
}
และคุณมีมัน วิธีที่ง่ายและสามส่วนในการตรวจสอบการใช้ปุ่มย้อนกลับเทียบกับองค์ประกอบในหน้าเกี่ยวกับการนำทางแฮช
แก้ไข:
เพื่อให้แน่ใจว่าผู้ใช้ไม่ได้ใช้ backspace เพื่อทริกเกอร์เหตุการณ์ย้อนกลับคุณสามารถรวมสิ่งต่อไปนี้ (ขอบคุณ @thetoolman ในคำถามนี้ ):
$(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
ตัวจัดการเหตุการณ์เช่น:
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()
วิธีการที่เรียกว่า programatically
event.state
เป็นทรัพย์สินของเหตุการณ์ที่เกิดขึ้นจะมีค่าเท่ากับรัฐวัตถุประวัติศาสตร์
สำหรับไวยากรณ์ jQuery ให้ล้อมรอบ (เพื่อเพิ่มฟังคู่หลังจากเอกสารพร้อม):
(function($) {
// Above code here.
})(jQuery);
ดูเพิ่มเติมที่: window.onpopstate เมื่อโหลดหน้าเว็บ
ดูยังมีตัวอย่างในหน้าเดียวปพลิเคชันและ HTML5 pushStateหน้านี้:
<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+, IE 10+, 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
}
}
แจ้งให้เราทราบหากสิ่งนี้ช่วยได้ หากฉันพลาดบางสิ่งฉันก็ยินดีที่จะเข้าใจ
event
มีค่าแม้สำหรับปุ่มไปข้างหน้า
ในจาวาสคริปต์ประเภทการนำทาง2
หมายถึงการคลิกปุ่มย้อนกลับหรือไปข้างหน้าของเบราว์เซอร์และเบราว์เซอร์กำลังนำเนื้อหาจากแคช
if(performance.navigation.type == 2)
{
//Do your code here
}
สิ่งนี้จะใช้ได้จริง (สำหรับการตรวจจับคลิกปุ่มย้อนกลับ)
$(window).on('popstate', function(event) {
alert("pop");
});
ดูนี่:
history.pushState(null, null, location.href);
window.onpopstate = function () {
history.go(1);
};
มันใช้งานได้ดี ...
if (window.performance && window.performance.navigation.type == window.performance.navigation.TYPE_BACK_FORWARD) {
alert('hello world');
}
นี่เป็นทางออกเดียวที่ได้ผลสำหรับฉัน (ไม่ใช่เว็บไซต์ onepage) มันทำงานร่วมกับ Chrome, Firefox และ Safari
คำตอบที่ถูกต้องมีอยู่แล้วเพื่อตอบคำถาม ฉันต้องการที่จะพูดถึงใหม่ 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);
}
เบราว์เซอร์: 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>
นี่คือสิ่งที่ฉันทำ สมมติฐานคือเมื่อ URL เปลี่ยนแปลง แต่ไม่มีการคลิกภายในสิ่งที่document
ตรวจพบมันเป็นเบราว์เซอร์กลับมา (ใช่หรือส่งต่อ) การคลิกของผู้ใช้จะถูกรีเซ็ตหลังจาก 2 วินาทีเพื่อให้ทำงานบนหน้าเว็บที่โหลดเนื้อหาผ่าน Ajax:
(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);
ฉันสามารถใช้คำตอบบางอย่างในชุดข้อความนี้และอื่น ๆ เพื่อให้ทำงานได้ใน 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();
}
ส่วนประกอบที่เต็มเปี่ยมสามารถใช้งานได้ต่อเมื่อคุณกำหนด API ใหม่ (เปลี่ยนวิธีการของวัตถุ 'ประวัติ') ฉันจะแบ่งปันคลาสที่เพิ่งเขียน ทดสอบกับ Chrome และ Mozilla Support เท่านั้น HTML5 และ ECMAScript5-6
class HistoryNavigation {
static init()
{
if(HistoryNavigation.is_init===true){
return;
}
HistoryNavigation.is_init=true;
let history_stack=[];
let n=0;
let current_state={timestamp:Date.now()+n};
n++;
let init_HNState;
if(history.state!==null){
current_state=history.state.HNState;
history_stack=history.state.HNState.history_stack;
init_HNState=history.state.HNState;
} else {
init_HNState={timestamp:current_state.timestamp,history_stack};
}
let listenerPushState=function(params){
params=Object.assign({state:null},params);
params.state=params.state!==null?Object.assign({},params.state):{};
let h_state={ timestamp:Date.now()+n};
n++;
let key = history_stack.indexOf(current_state.timestamp);
key=key+1;
history_stack.splice(key);
history_stack.push(h_state.timestamp);
h_state.history_stack=history_stack;
params.state.HNState=h_state;
current_state=h_state;
return params;
};
let listenerReplaceState=function(params){
params=Object.assign({state:null},params);
params.state=params.state!==null?Object.assign({},params.state):null;
let h_state=Object.assign({},current_state);
h_state.history_stack=history_stack;
params.state.HNState=h_state;
return params;
};
let desc=Object.getOwnPropertyDescriptors(History.prototype);
delete desc.constructor;
Object.defineProperties(History.prototype,{
replaceState:Object.assign({},desc.replaceState,{
value:function(state,title,url){
let params={state,title,url};
HistoryNavigation.dispatchEvent('history.state.replace',params);
params=Object.assign({state,title,url},params);
params=listenerReplaceState(params);
desc.replaceState.value.call(this,params.state,params.title,params.url);
}
}),
pushState:Object.assign({},desc.pushState,{
value:function(state,title,url){
let params={state,title,url};
HistoryNavigation.dispatchEvent('history.state.push',params);
params=Object.assign({state,title,url},params);
params=listenerPushState(params);
return desc.pushState.value.call(this, params.state, params.title, params.url);
}
})
});
HistoryNavigation.addEventListener('popstate',function(event){
let HNState;
if(event.state==null){
HNState=init_HNState;
} else {
HNState=event.state.HNState;
}
let key_prev=history_stack.indexOf(current_state.timestamp);
let key_state=history_stack.indexOf(HNState.timestamp);
let delta=key_state-key_prev;
let params={delta,event,state:Object.assign({},event.state)};
delete params.state.HNState;
HNState.history_stack=history_stack;
if(event.state!==null){
event.state.HNState=HNState;
}
current_state=HNState;
HistoryNavigation.dispatchEvent('history.go',params);
});
}
static addEventListener(...arg)
{
window.addEventListener(...arg);
}
static removeEventListener(...arg)
{
window.removeEventListener(...arg);
}
static dispatchEvent(event,params)
{
if(!(event instanceof Event)){
event=new Event(event,{cancelable:true});
}
event.params=params;
window.dispatchEvent(event);
};
}
HistoryNavigation.init();
// exemple
HistoryNavigation.addEventListener('popstate',function(event){
console.log('Will not start because they blocked the work');
});
HistoryNavigation.addEventListener('history.go',function(event){
event.params.event.stopImmediatePropagation();// blocked popstate listeners
console.log(event.params);
// back or forward - see event.params.delta
});
HistoryNavigation.addEventListener('history.state.push',function(event){
console.log(event);
});
HistoryNavigation.addEventListener('history.state.replace',function(event){
console.log(event);
});
history.pushState({h:'hello'},'','');
history.pushState({h:'hello2'},'','');
history.pushState({h:'hello3'},'','');
history.back();
```
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 ธรรมดา
<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
}
});
รหัสข้างต้นใช้งานได้สำหรับฉัน บนเบราว์เซอร์มือถือเมื่อผู้ใช้คลิกที่ปุ่มย้อนกลับเราต้องการเรียกคืนสถานะหน้าเว็บตามการเข้าชมครั้งก่อน
ฉันแก้ไขมันโดยการติดตามเหตุการณ์ดั้งเดิมที่ก่อให้เกิด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)
}
ฉันลองตัวเลือกด้านบน แต่ไม่มีตัวใดที่ทำงานให้ฉันได้ นี่คือทางออก
if(window.event)
{
if(window.event.clientX < 40 && window.event.clientY < 0)
{
alert("Browser back button is clicked...");
}
else
{
alert("Browser refresh button is clicked...");
}
}
อ้างอิงลิงค์นี้http://www.codeproject.com/Articles/696526/Solution-to-Browser-Back-Button-Click-Click-Event-Handliสำหรับรายละเอียดเพิ่มเติม