Saya telah membuat aplikasi web yang menggunakan history
pushState
danreplaceState
metode untuk menavigasi halaman sambil memperbarui sejarah.
Script itu sendiri hampir berfungsi dengan sempurna; itu akan memuat halaman dengan benar, dan membuang kesalahan halaman ketika mereka perlu dilempar. Namun, saya perhatikan ada masalah aneh di mana pushState
akan mendorong banyak entri, duplikat (dan mengganti entri sebelumnya) ke riwayat.
Sebagai contoh, katakanlah saya melakukan hal berikut (secara berurutan):
Muat index.php (sejarah akan menjadi: Indeks)
Navigasikan ke profile.php (riwayatnya adalah: Profil, Indeks)
Arahkan ke search.php (riwayatnya adalah: Cari, Cari, Indeks)
Arahkan ke dashboard.php
Lalu akhirnya, inilah yang akan muncul dalam sejarah saya (dalam urutan terbaru hingga tertua):
Dashboard
Dashboard
Dashboard
Cari
Indeks
Masalahnya adalah ketika pengguna mengklik tombol maju atau mundur, mereka akan diarahkan ke halaman yang salah, atau harus mengklik beberapa kali untuk kembali sekali. Itu, dan tidak masuk akal jika mereka pergi dan memeriksa sejarah mereka.
Inilah yang saya miliki sejauh ini:
var Traveller = function(){
this._initialised = false;
this._pageData = null;
this._pageRequest = null;
this._history = [];
this._currentPath = null;
this.abort = function(){
if(this._pageRequest){
this._pageRequest.abort();
}
};
// initialise traveller (call replaceState on load instead of pushState)
return this.init();
};
/*1*/Traveller.prototype.init = function(){
// get full pathname and request the relevant page to load up
this._initialLoadPath = (window.location.pathname + window.location.search);
this.send(this._initialLoadPath);
};
/*2*/Traveller.prototype.send = function(path){
this._currentPath = path.replace(/^\/+|\/+$/g, "");
// abort any running requests to prevent multiple
// pages from being loaded into the DOM
this.abort();
return this._pageRequest = _ajax({
url: path,
dataType: "json",
success: function(response){
// render the page to the dom using the json data returned
// (this part has been skipped in the render method as it
// doesn't involve manipulating the history object at all
window.Traveller.render(response);
}
});
};
/*3*/Traveller.prototype.render = function(data){
this._pageData = data;
this.updateHistory();
};
/*4*/Traveller.prototype.updateHistory = function(){
/* example _pageData would be:
{
"page": {
"title": "This is a title",
"styles": [ "stylea.css", "styleb.css" ],
"scripts": [ "scripta.js", "scriptb.js" ]
}
}
*/
var state = this._pageData;
if(!this._initialised){
window.history.replaceState(state, state.title, "/" + this._currentPath);
this._initialised = true;
} else {
window.history.pushState(state, state.title, "/" + this._currentPath);
}
document.title = state.title;
};
Traveller.prototype.redirect = function(href){
this.send(href);
};
// initialise traveller
window.Traveller = new Traveller();
document.addEventListener("click", function(event){
if(event.target.tagName === "a"){
var link = event.target;
if(link.target !== "_blank" && link.href !== "#"){
event.preventDefault();
// example link would be /profile.php
window.Traveller.redirect(link.href);
}
}
});
Semua bantuan dihargai,
Ceria.
sumber
updateHistory
fungsi Anda . Sekarang,updateHistory
mungkin dipanggil dua kali, 1, ketika Anda menginisialisasi Traveler (window.Traveller = new Traveller();
,constructor
->init
->send
->render
->updateHistory
), kemudian juga olehredirect
dariclick
eventListener. Saya belum mengujinya, hanya menebak-nebak, jadi menambahkannya sebagai komentar dan bukan jawaban.Jawaban:
Apakah Anda memiliki pengendali onpopstate ?
Jika ya, periksa juga di sana jika Anda tidak mendorong ke sejarah. Bahwa beberapa entri dihapus / diganti dalam daftar riwayat mungkin merupakan pertanda besar. Memang, lihat jawaban SO ini :
Saya pernah memiliki masalah yang sama persis seperti yang Anda gambarkan, tetapi sebenarnya disebabkan oleh saya bolak-balik untuk mencoba memahami bug, yang pada akhirnya akan memicu popState handler. Dari pengendali itu, ia akan memanggil history.push. Jadi pada akhirnya, saya juga memiliki beberapa entri yang digandakan, dan beberapa hilang, tanpa penjelasan logis.
Saya menghapus panggilan ke history.push, menggantinya dengan history.replace setelah memeriksa beberapa kondisi, dan setelah itu berfungsi seperti pesona :)
EDIT -> TIP
Jika Anda tidak dapat menemukan kode mana yang memanggil history.pushState:
Coba timpa fungsi history.pushState dan gantiState dengan kode berikut:
Kemudian setiap kali breakpoint dipicu, lihat ke tumpukan panggilan.
Di konsol, jika Anda ingin mencegah pushState, cukup masukkan
allowPush = false;
atauallowReplace = false;
sebelum melanjutkan. Dengan cara ini, Anda tidak akan melewatkan history.pushState, dan dapat naik dan menemukan kode yang memanggilnya :)sumber