Я создал веб - приложение , которое использует history
pushState
и replaceState
методы для того , чтобы перемещаться по страницам , а также обновление истории.
Сам скрипт работает почти идеально; он будет загружать страницы правильно, и выдает ошибки страниц, когда их нужно выбросить. Тем не менее, я заметил странную проблему, когда pushState
в историю помещаются несколько повторяющихся записей (и заменяются записи перед ними).
Например, допустим, я делаю следующее (по порядку):
Загрузите index.php (история будет: Index)
Перейдите к profile.php (история будет: Профиль, Индекс)
Перейдите к search.php (история будет: Поиск, Поиск, Индекс)
Перейдите к dashboard.php
И, наконец, вот что всплывет в моей истории (в порядке от самых последних до самых старых):
Приборная панель
Приборная панель
Приборная панель
Search
Index
Проблема заключается в том, что когда пользователь нажимает кнопки «вперед» или «назад», они либо перенаправляются на неправильную страницу, либо вынуждены нажимать несколько раз, чтобы вернуться назад один раз. Это, и не будет никакого смысла, если они пойдут и проверит свою историю.
Это то, что я до сих пор:
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);
}
}
});
Вся помощь приветствуется,
ура.
источник
updateHistory
функцию. Теперь,updateHistory
может быть, вызывается дважды, во-первых, когда вы инициализируете Traveler (window.Traveller = new Traveller();
,constructor
->init
->send
->render
->updateHistory
), затем такжеredirect
изclick
EventListener. Я не проверял это, просто дикие догадки, поэтому добавлял это как комментарий, а не как ответ.Ответы:
У вас есть обработчик onpopstate ?
Если да, то проверьте там также, если вы не настаиваете на истории. То, что некоторые записи удалены / заменены в списке истории, может быть большим признаком. В самом деле, посмотрите этот так ответ :
Однажды у меня была точно такая же проблема, как вы описали, но на самом деле это было вызвано тем, что я возвращался назад и вперед, чтобы попытаться понять ошибку, которая в конечном итоге вызовет обработчик popState. Из этого обработчика он будет вызывать history.push. Итак, в конце у меня также было несколько дублированных записей, а некоторые отсутствовали без какого-либо логического объяснения.
Я удалил вызов history.push, заменил его на history.replace после проверки некоторых условий и после того, как он заработал как брелок :)
РЕДАКТИРОВАТЬ -> СОВЕТ
Если вы не можете определить, какой код вызывает history.pushState:
Попробуйте перезаписать функции history.pushState и replaceState следующим кодом:
Затем каждый раз, когда точки останова срабатывают, взгляните на стек вызовов.
В консоли, если вы хотите предотвратить pushState, просто введите
allowPush = false;
илиallowReplace = false;
перед возобновлением. Таким образом, вы не пропустите ни одного файла history.pushState, а сможете подняться и найти код, который его вызывает :)источник