Académique Documents
Professionnel Documents
Culture Documents
history
EduardoCasas ProgramadorenMadrid
ElobjetohistorydeJavaScriptcontieneunalistadelasURLquehemosvisitadoenelmismotab,entrelascualespodemosdesplazarnos
yaccederaellas.AntesdelallegadadeHTML5esteobjetoresultabaintildecaraatrabajarconaplicacionesbasadasenAJAX,teniendo
que recurrir a otros mtodos menos naturales y limitados. Sin embargo, el desarrollo de su especificacin lo ha convertido en el
complementoidealparatrabajarconestatecnologa.
Hastaahora,elobjetohistory(asuvezpropiedaddelobjeto"window")disponadetresmtodosquenospermitaninteraccionarconelhistorial
denavegacindenuestronavegador:
back():cargalaURLdelestadoanterior
forward():cargalaURLdelestadosiguiente
go(nmero):cargalaURLdelestadoindicadoenelparámetro
Yunanicapropiedad:
length:indicaelnmerodeelementosdisponiblesenelhistorialdenavegacin
Aunqueexistanalternativasgraciasaleventohaschange,estosmtodosresultabaninsuficentesalahoradetrabajarconpginascargadaspor
mediodeAJAX,puestoquenohabamaneradeasociarunestadoalhistorial,demaneraquealretroceder/avanzarpormediodelosbotonesde
nuestronavegadorseperdalainformacin.
Peroeldesarrollodelobjetonoshatraidodosnuevosmtodos(pushStateyreplaceState)quesolucionanesteproblema,ademsdeotranueva
propiedadstate:
El mtodo pushState aade un nuevo estado a nuestra lista mientras que replaceState sustituye el estado actual. Como veremos, ambos
mtodosfuncionandeformamuyparecidayrequirentresparmetros:
state:jsonquereprentaelestadodelnuevoelementoaadidoalhistorial
title:titulodelnuevoelemento(noconfundirconelcontenidodelelementotitledehtml).Esteparmetroannoessoportadoenlamayora
denavegadoresporloqueledaremosunvalornull.
url:URL(relativaoabsoluta)asociadaalnuevoelemento
Porotrolado,lanuevapropiedadstatedevuelveelvalordelestadoenelquenosencontramos,sintenerquedependerdeleventopopstate.
ParaestudiarlaimplementacindelasnuevascaractersticasdelobjetohistoryenunaaplicacinAJAXhecreadounapequeoejemplocuyo
repositorio he subido a github. Esta aplicacin est desarrollada en PHP y jQuery y consta de los siguientes elementos: el fichero de entrada
index.php,elcualcontienelaplantillayseencargadellamaralasvistascontenidosenlacarpetaviewslacarpetajsquecontienelalibrerade
jQueryyelficherofile.jsquecontienelasllamadasalosmtodosdelobjetohistoryunfichero.htaccessparaforzarelpatrnfrontcontroller.
Empezamosporesteltimo:
1 #.htaccess ?
2
3 RewriteEngineon
4
5 nRewriteCond%{REQUEST_FILENAME}!f
6 RewriteRule^(.*)$index.php[L]
Aqusimplementeforzamosunnicopuntodeentrada(elficheroindex.php)siemprequelaurlnocorrespondaaladeunficheroexistenteen
nuestraapp.
Elficheroindex.php:
1 //index.php
https://www.eduardocasas.com/es/blog/18112012/ajaxyelobjetowindowhistory 1/5
2017519 AJAXyelobjetowindow.history
1 //index.php ?
2
EduardoCasas ProgramadorenMadrid
3 <?php
4 $uri=explode('/',$_SERVER['REQUEST_URI']);
5 $view=end($uri);
6 if(empty($view)||$view==='index.php'){
7 header('location:index');
8 }
9 ?>
10 <!DOCTYPEhtml>
11 <htmllang="es">
12 <head>
13 <metacharset="UTF8">
14 <title>historyObjectExample</title>
15 &
16 lt;scriptsrc="js/jquery.js"></script>
17 <scriptsrc="js/file.js"></script>
18 </head>
19 <body>
20 <nav>
21 <?phpinclude'views/'.$view.'.html';?>
22 </nav>
23 <buttonid="previous">Previous</button>
24
25 <buttonid="forward">Forward</button>
26 <p>Numberofpagesinthehistorystack:<span><span></p>
27 </body>
28 </html>
ElscriptenPHPidentificaelslugdelaurlparaasociarlavistacorrespondiente.Pordefectoser"index".ElcdigoHTMLcontienelaplantilla,la
cualestcompuestadeunmendenavegacindefinidoporlavista,dosbotonesquenospermitenmovernosatravsdenuestrohistorialde
navegacin(anlogosalosbotonesatrsyadelantedenuestronavegador)yuntextoqueindicaelnmerodeelementosincluidoslalista.
Las vistas las he hecho lo ms sencillas posibles y nicamente contienen el men de navegacin, resaltando el elemento que se corresponde
conlapropiavista:
1 <!views/index.html> ?
2
3 <ul>
4 <li><strong>index</strong></li>
5 <li><ahref="page1">page1</a></li>
6 <
7 li><ahref="page2">page2</a></li>
8 </ul>
9
10 <!views/page1.html>
11
12 <ul>
13 <li><ahref="index">index</a></li>
14 <li><strong>page1</strong></li>
15 <li><ahref="page2">page2</a></li>
16 </ul>
17
18 <!views/page2.html>
19
20 <ul>
21 <li><ahref="index">index</a></li>
22 <li><ahref="page1">page1</a></li>
23 <li><strong>page2</strong>&
24 lt;/li>
25 </ul>
Yporltimo,elficherofile.jsqueeselquerealmentenosinteresa:
1 //js/file.js ?
2
3 $(document).ready
4 (
5 function()
6 {
7 $('#previous').click
8 (
9 function()
10 {
11 window.history.back();
12 }
13 );
14 $('#forward').click
15 (
16
17 function()
18 {
19 window.history.forward();
20 }
21 );
22 functionloadView(view)
23 {
24 $('nav').load('views/'+view+'.html');
https://www.eduardocasas.com/es/blog/18112012/ajaxyelobjetowindowhistory 2/5
2017519 AJAXyelobjetowindow.history
24 $('nav').load('views/'+view+'.html');
25 }
EduardoCasas ProgramadorenMadrid
26 functionprintHistoryLength()
27 {
28 $('span').text(window.history.length);
29 }
30 $('nav').on
31 (
32 'click',
33 'a',
34 function(event)
35 {
36 if(typeofwindow.history.pushState=='
37 function'){
38 event.preventDefault();
39 varview=$(this).attr('href');
40 window.history.pushState(view,null,view);
41 loadView(view);
42 printHistoryLength();
43 }
44 }
45 );
46 window.history.replaceState($('strong').text(),null,$('strong').text());
47 printHistoryLength();
48 r
49 window.onpopstate=function(event)
50 {
51 loadView(window.history.state);
52 };
53 }
54 );
Vamosaestudiarestedocumentoporpartes:
1 $('#previous').click ?
2 (
3 function()
4 {
5 window.history.back();
6 }
7 );
8 $('#forward').click
9 (
10 function()
11 {
12 window.history.forward();
13 }
14 );
Estas funciones asociadas al evento click para los botones #previous y #forward nos permiten simular el comportamiento de los botones del
navegador"Atrs"(mtodowindow.history.back)y"Adelante"(window.history.forward),respectivamente.
1 functionloadView(view) ?
2 {
3 $('nav').load('views/'+view+'.html');
4 }
5 functionprintHistoryLength()
6 {
7 $('span').text(window.history.length);
8 }
Paranorepetircdigo,declaramoslasfuncionesloadViewyprintHistoryLength.LaprimeracargavaAJAXlasvistascontenidasenlacarpeta
view mediante el mtodo load de jQuery . La segunda simplemente pinta el nmero de elementos almacenados en nuestro historial de
navegacin.
1 $('nav').on ?
2 (
3 'click',
4 'a',
5 function(event)
6 {
7 if(typeofwindow.history.pushState=='function'){
8 event.preventDefault();
9 varview
10 =$(this).attr('href');
11 window.history.pushState(view,null,view);
12 loadView(view);
13 printHistoryLength();
14 }
15 }
16 );
AqumesirvodelmtodoondejQuery(>=1.7)necesarioparapoderasociareleventoclickalosenlacesdelmendenavegacindelasvistas
cargadasvaAJAX.
https://www.eduardocasas.com/es/blog/18112012/ajaxyelobjetowindowhistory 3/5
2017519 AJAXyelobjetowindow.history
Lo primero que hacemos es comprobar si el navegador soporta el mtodo history.pushState. De ser as, invocamos dicho mtodo al que
EduardoCasas ProgramadorenMadrid
pasamosalosparmetros"state"y"url"lavariableurl,lacualcorrespondeconelslugalqueapuntaelenlaceencuestin.Comonovamosa
utilizar el parmetro "title", le damos un valor nulo. Una vez aadido el nuevo estado, podemos observar como por arte de magia la URL de
nuestronavegadorcambiaalvalordado.AcontinuacinllamamosalasfuncionesloadView,alaquelepasamoscomoparmetrodichoslug,y
printHistoryLength.
Encasodequeelnavegadornosoporteelmtodo,laaplicacinsecomportardemaneranaturalrecargandolapginaalabrirelnuevoenlace
.
1 window.history.replaceState($('strong').text(),null,$('strong').text()); ?
2 printHistoryLength();
Estas dos lneas son necesarias al cargar la pgina inicial. Para poder asignarle un estado (por defecto siempre es null) debemos invocar el
mtodohistory.replaceStatepasandoelvalordelslugdelapginaactualalosparmetros"state"y"url".Delocontrarionopodramosaccedera
ellapormediodelhistorialdenavegacin.AcontinuacinllamamosalafuncinprintHistoryLengthparapintarelnmerodesitiosalmacenados
en la lista. Notar que si en su lugar hubieramos utilizado el mtodo replaceState, al recargar la pgina el nmero de sitios almacenados
aumentaraen+1(algoqueenunprincipionodeberainteresarnos).
1 window.onpopstate=function(event) ?
2 {
3 loadView(window.history.state);
4 };
Porltimodefinimoslafuncinasociadaaleventopopstate,lacualselanzarcadavezquenaveguemosatravsdelhistorial.Hayqueteneren
cuenta que para poder visualizar el contenido de cada estado almacenado debemos llamar a la funcin loadView y pasarle el slug como
parmetro, de lo contrario podramos desplazarnos por el historial pero, logicamente, no se cargara la vista asociada. Es decir, lo que en
realidadhacemosessimularlasaccionesderetroceder/avanzarentrelaspginasalmacenadasennuestrohistorial.
Por cierto, sealar que tambin podramos haber utilizado la propiedad event.state en lugar de history.state, aunque de esta manera nos
ahorramosproblemasconGoogleChrome.Debemostenerencuentaqueestenavegadordisparaeleventoonpopstatecadavezquesecarga
una pgina, de manera que en nuestro caso, al cargar la pgina inicial la propiedad event.sate habra devuelto un valor nulo, saltando por lo
tantounerrorenlaaplicacin.
Dichotodoesto,debemossaberquesiguendndosealgunosproblemas.Elmsobvio,queenGoogleChromeelcontenidodenuestrapgina
inicial ser cargado dos veces (primero por PHP y luego por AJAX debido al evento popstate), lo que no es para nada deseable. Adems,
tambinexistenincompatibilidadesconalgunasversionesantiguasdeSafariyOpera.Paraevitarestosproblemasyfacilitarsuimplementacin
crossbrowserBenjaminLuptonhacreadolalibreriahistory.jsqueademsescompatibleconframeworkscomojQueryoMootools.
Comentarios
Identifcateparaescribiruncomentario.
Noexistencomentariosparaesteartculo.
License:CreativeCommonsAttribution3.0Unported
PoweredbySymfony3
ForkmeonGitHub
https://www.eduardocasas.com/es/blog/18112012/ajaxyelobjetowindowhistory 4/5
2017519 AJAXyelobjetowindow.history
https://www.eduardocasas.com/es/blog/18112012/ajaxyelobjetowindowhistory 5/5