Войти через VK Войти через FB Войти через Google Войти через Яндекс
Поиск по сайту
История и навигация в HTML5. Методы pushState и replaceState
В html5 появились возможности навигации без перезагрузки страницы, при этом корректно отрабатывается функции "назад" и "вперед" браузера.
Для этого используется следующий функционал:
history.pushState(obj, title, Url);
history.replaceState(obj, title, Url);
и обработчик
onpopstate
Приведенный здесь скрипт имеет несколько отличительных особенностей от множества примеров в интернете:
- скрипт корректно отрабатывает внутренние ссылки: <a name=""></a>;
- изменяется тег base. Иначе после загрузки контента все ссылки будут указывать "не туда";
- подгружается заголовок страницы;
- учитывается, нажата ли с кликом мыши клавиша Ctrl или Shift для отмены загрузки через обработчик;
- отрабатывается работа через hash, при отстутствии поддержки html5 браузером.
Объект, в котором будет меняться содержимое:
<div id="main"></div>
Серверная часть должна предусматривать обработку дополнительного GET-параметра ajax=1, при котором возвращается только тело страницы, без обрамления. Т.е. только то, что нужно загрузить в DIV-блок.
Для смены заголовка страницы можно дополнительно передать:
<title>ЗАГОЛОВОК</title>
Если в теле странцы есть элемент Base, его содержимое при подгрузке страницы будет перезаписано.
Для загрузки содержимого страницы (или части страницы) без перезагрузки используется следующий скрипт:
var oldUrl=document.location;
var MainUrl='';
function LoadMain(e0){
e=e0||window.event;
if(e){if(e.ctrlKey||e.shiftKey)return true;} // если нажата Ctrl или Shift, то загружать в отдельном окне
if(e0 && e0.stopPropagation){e0.stopPropagation();e0.preventDefault();} // для DOM-совместимых браузеров
else window.event.cancelBubble=true; //для IE
url=getEventTarget(e0);
if(url.nodeName!='A'&&url.parentNode)url=url.parentNode;
if(url.href)url=url.href;
LoadMainUrl(url);
if(history.pushState)history.pushState(null, null, MainUrl);
else window.location.hash='#'+MainUrl;
return false;
}
function ajaxLoad(obj,url,defMessage,post,callback){
var ajaxObj;
if(typeof(obj)!="object")obj=document.getElementById(obj);
if(defMessage)obj.innerHTML=defMessage;
if(window.XMLHttpRequest){
ajaxObj = new XMLHttpRequest();
} else if(window.ActiveXObject){
ajaxObj = new ActiveXObject("Microsoft.XMLHTTP");
} else {
return;
}
ajaxObj.open ((post?'POST':'GET'), url);
if(post&&ajaxObj.setRequestHeader){
ajaxObj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8;");
}
ajaxObj.setRequestHeader("Referer", window.location.href);
ajaxObj.onreadystatechange = ajaxCallBack(obj,ajaxObj,(callback?callback:null));
ajaxObj.send(post);
return false;
}
try{
setTimeout( function() {
window.addEventListener("popstate", function(e) {
MainUrl=e.location || document.location;
if(oldUrl.pathname==MainUrl.pathname && oldUrl.hash.substring(1,1)!='/'){
/*alert(oldUrl.pathname+'|'+MainUrl.pathname+'|'+oldUrl.hash);*/
return;}
LoadMainUrl(MainUrl.href);
}, false);
}, 900 );
}catch(e){};
function LoadMainUrl(url){
e=window.location.hostname;
MainUrl=url;
i=url.indexOf(e); if(i>0)url=url.substring(i+e.length);
if(url.substring(0,1)!='/')return;
i=url.indexOf('#');
if(i>0)url=url.substring(0,i)+(url.indexOf('?')>=0?'&':'?')+'ajax=1'+url.substring(i);
else url=url+(url.indexOf('?')>=0?'&':'?')+'ajax=1';
ajaxLoad('main',url,'Загрузка...')
}
function updateObj(obj, data){
if(typeof(obj)!="object")obj=document.getElementById(obj); if(!obj)return;
if(obj.id=='main'){
var re1=new RegExp ("<title>([^<]+)</title>","i"); text=re1.exec(data);
if(text!=null){t=text[1]; document.title=t;
data=data.replace(re1, "");
}
obj.innerHTML=data;
el=document.getElementsByTagName('base')[0];
if(!el){el=document.createElement("base");
document.getElementsByTagName('head')[0].appendChild(el);}
el.setAttribute('href', MainUrl);
oldUrl=MainUrl;
window.scroll(0,0);
return;
}
obj.innerHTML = data;
}
function ajaxCallBack(obj, ajaxObj, callback){
return function(){
if(ajaxObj.readyState==4){
if(callback) if(!callback(obj,ajaxObj))return;
if (ajaxObj.status==200){
updateObj(obj, ajaxObj.responseText);
}
else updateObj(obj, ajaxObj.status+' '+ajaxObj.statusText);
}
;
}}
function getEventTarget(e) {
var e = e || window.event;
var target=e.target || e.srcElement;
if(typeof target == "undefined")return e; // передали this, а не event
if (target.nodeType==3) target=target.parentNode;// боремся с Safari
return target;
}
Назначение обработчика загрузки на ссылку:
<a href="/html/" onclick="return LoadMain(this)">Html</a>
Если Вы хотите на все ссылки установить загрузку через свой обработчик, используйте следующий код:
addEvent(examples, 'click', function (event) {
event.preventDefault();
if (event.target.nodeName == 'A') {
LoadMain(event);
/*title = event.target.innerHTML;
data[title].url = event.target.getAttribute('href');
history.pushState(data[title], title, event.target.href);*/
}
});
Еще один пример использования сохранения адреса:
u="http://"+document.location.host+document.location.pathname+document.location.search;
hash=document.location.hash; // после #
console.log(u,hash);
if(u.indexOf('?')>=0)u=(u+'&').replace(/url=(.*?)&/gi,"").replace(/&&/gi,"&");
var i=u.substr(u.length-1,1);
if(i=='?'||i=='&')u=u.substr(0,u.length-1);
u=u+(u.indexOf('?')>=0?'&':'?')+"url="+encodeURIComponent(url)+hash;
MainUrl=u;
if(history.pushState)history.pushState(null, null, MainUrl);
Интерфейс History html5
Приведено описание наболее важных компонентов.
interface History {
void pushState(in any data, in DOMString title, in optional DOMString url);
void replaceState(in any data, in DOMString title, in optional DOMString url);
};
interface HTMLBodyElement : HTMLElement {
attribute Function onpopstate;
};
Эмулятор pushState и onpopstate
// сохранение ссылки в location.hash
function _pushState(state) {
window.location.hash = state;
}
// обнаружение изменения в location.hash
var lastState;
window.setTimeout(function() {
var state = window.location.hash;
if (lastState != state) {
lastState = state;
LoadMain(state);
}
}, 100);
.
Прокомментировать/Отблагодарить