AJAX a navigace v historii stránek

9.2.2009  |  Dzaky

Vracel jsem se ze zkoušky domů a zničeho nic jsem začal přemýšlet o AJAXu a všeobecně zastávaném názoru, že při použití této technologie není možné se pohybovat po stránce tlačítky Zpět a Vpřed. Říkal jsem si „tak a teď objevím Ameriku (opět) a všem vytřu zrak“. Ukázalo se, že Ameriku neobjevím, ale aspoň budu mít námět na nový článek.

Když jsem dorazil domů, nelenil jsem a při první příležitosti jsem sednul k počítači a jal se studovat API prohlížeče Firefox. První nápad, který jsem měl byl založen na teorii, že prohlížeče by přes své API mohli zpřístupňovat události, které by následně bylo možno odchytávat JavaScriptem. Pokud by tomu tak bylo, stačilo by již pouze přizpůsobit JS kód pro každého zástupce z majoritních prohlížečů, napojit AJAX a teoreticky by to mohlo fungovat. „Studium“ API Firefoxe bohužel nepřineslo v tomto směru žádné hodnotné informace. Pomalu jsem myšlenku na navigaci mezi stránkami tlačítky Zpět a Vpřed vypudil z hlavy, až jsem na ní zcela zapomněl. Shoda okolností mně tři dny na to donutila přihlásit se ke svému gmail účtu skrze webový prohlížeč a jak jsem si tam tak klikal, uvědomil jsem si jednu věc: gmail je přece AJAXová aplikačka, a funguje navigace mezi stránkami pomocí tlačítek. Zrak mi spočinul na adresní řádce a v ten moment mi to došlo.

Řešení

Standard HTML i XHTML umožňuje používat tzv. kotvy. Tedy dáte tagu <a> parametr name="kotva" a na tuto kotvu se můžete odkudkoliv ze stránky dostat kliknutím na odkaz <a href="#kotva">. Adresní řádka se následně změní, ze stránky www.stranka.cz se stane www.stranka.cz#kotva, prohlížeč detekuje „změnu“ adresy a uloží stránku do historie. Tato kotva, resp. její řetězec je následně z JavaSciptu přístupná skrze objekt location a jeho metodu hash. Tedy location.hash.

Samotná implementace se skládá ze dvou kusů kódu. V první řadě je potřeba při volání AJAXové metody "přepsat" kotvu a následně musíme být schopni změnu kotvy detekovat.

Odpovídající úprava XMLHttpRequest

Již před více než rokem jsem začal seriál o AJAXu a základech použití této technologie. Ukázali jsme si, jak podle prohlížeče inicializovat XMLHttpRequest, odeslat požadavek na server, počkat si na odpověď a tu případně zpracovat a provést danou akci se stránkou.

Do tohoto kódu budeme muset vložit dva řádky (modře označeno), které zajistí že se URL změní, resp. přidá se k ní již zmiňovaná kotva, aby prohlížeč mohl detekovat změnu URL a uložit ji do historie. Tento kompletní kód by tedy mohl vypadat nějak takto:



var XMLHttpRequestObject = false;

if (window.XMLHttpRequest) {
  XMLHttpRequestObject = new XMLHttpRequest();
} else if (window.ActiveXObject) {
  XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP");
}
function getData(dataSource, divID) {
  if(XMLHttpRequestObject) {
    var obj = document.getElementById(divID);
    XMLHttpRequestObject.open("GET", dataSource+".html");

    document.location.hash = "#"+dataSource;
    urlHash = document.location.hash;

    XMLHttpRequestObject.onreadystatechange = function() {
      if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200) {
        obj.innerHTML = XMLHttpRequestObject.responseText;
      }
    }

    XMLHttpRequestObject.send(null);
    return false;
  }
}

Odchytávání změny URL, resp. kotvy

Abychom ale mohli uživateli správně načítat stránky předchozí (či následující), budeme muset odchytávat „událost“ změny adresní řádky. Jelikož jsem nebyl schopen najít žádnou takovouto událost, je potřeba najít cestu oklikou. DOM poskytuje funkci setInterval, která má dva parametry. Prvním je kód či funkce, která se má po uplynutí daného času vykonat a druhým parametrem je samotný čas v milisekundách. Když vyprší daný čas, je volána zadaná funkce a časový interval běží od začátku.

Definujeme tedy globální proměnou, která bude obsahovat řetězec kotvy a nastavíme funkci setInterval aby vykonala funkci checkAnchor() každých 300 milisekund. Funkce checkAnchor bude následně porovnávat kotvu, která je uložena v globální proměnné s kotvou, kterou si načte z adresy. Pokud jsou rozdílné zavolá metodu getData s příslušnými parametry a ta se již postará o dotaz na data a jejich vytisknutí do stránky.



var url = window.location;
var urlHash = window.location.url;  // soucasna kotva (zadna)
var homePage = true;  // prvni nacteni stranky (zadny AJAX zatim nevykonan)

setInterval("checkAnchor()", 300);

function checkAnchor(){
  // kontrola jestli se zmenila kotva
  if(urlHash != document.location.hash && document.location.hash!=""){
    urlHash = document.location.hash; // nastavime zmenenou kotvu
    homePage = false; // uz byla ajaxem volana jina stranka

    var splits = urlHash.substring(1).split('&');
    var section = splits[0]; // retezec kotvy

    // zavolame funkci pro ziskani dat
    getData(section, 'content');
  }

  // pokud byl navrat na uvodni stranku
  if(document.location.hash=="" && homePage==false){
    document.location.reload();  // reloadujeme stranku
    homePage = true;  // aby se cyklicky nevracel na stranku
  }
}

Závěr

S tím vším, co bylo popsáno, dosáhneme AJAXové aplikace, která nediskriminuje uživatele s vypnutým JavaScriptem, vyhledávací roboty a rovněž uživateli zpřístupníme funkčnost tlačítek Zpět a Vpřed tak, jak je jejich funkčnost očekávána. Funkční demo je dostupné na této adrese. Záměrně jsem kvůli zjednodušení neřešil serverovou část, tato problematika by vystačila na samostatný článek a tímto článkem jsem chtěl pouze ukázat princip, postup chcete-li, jak dosáhnout AJAXové aplikace, která by neznemožnila indexaci obsahu a zároveň nezrušila navigaci v historii.

Dzaky   Vloženo: 13. 3. 2009 14:36   WWW    
Oběma díky za doplnění.

M. Hassman: Na událost hashchange jsem při brouzdání narazil, nicméně když nefungovala ve FF tak jsem ji okamžitě zavrhnul.

Maxell: přidávání komentářů ještě budu upravovat (až se k tomu dokopu :) však mně znáš )

Maxell   Vloženo: 10. 3. 2009 20:54   WWW    
Dobrej článek hele :-)

Jak psal Martin, SEO a vyhledávače tohle bohužel stále neřeší, protože stránka neco.cz/clanek/ a neco.cz/clanek/#anchor je v principu pořád jedna stránka (původní myšlenka anchor odkazu). To, že ve skutečnosti obsah může být odlišný (nejen díky AJAXu) je pravda, ale vyhledávače s tím nepočítají. Těžko říct, jestli by to taky bylo lepší, přidělalo by to spoustu nových problémů (duplicity např.) :-)

BTW upravil bych trochu chování komentů, nefachá mi přeskakování TABem a to, že email je povinej jsem se dozvěděl až po odeslání k náhledu :-)

Martin Hassman   Vloženo: 6. 3. 2009 9:28   WWW    
Ona událost, kterou jste hledal, se jmenuje hashchange. Je součástí HTML5, ale zatím ji implementoval pouze IE8.

Co se týče indexace roboty, tak tomu řešení s hashem nepomůže (hash je zpracováván jen na straně klienta, není odesílán na server). Myslím, že se jedná poslední nevýhodu AJAXu, kterou zatím ještě nikdo nevyřešil (tedy kromě cesty nabízení obsahu robotům alternativním způsobem).

Ostatní

Náhodné fotky

další náhodné
p1030816.jpg hpim9954.jpg p1100193.jpg