Você está aqui: Home ‣ Dive Into HTML5 ‣
❧
barra de endereços do navegador é talvez a peça mais antiga da interface de usuário no mundo. Há URLs em outdoors, nas laterais de trens, e até mesmo em grafites de rua. Combinado com o botão de voltar — provavelmente o botão mais importante do navegador — você tem uma maneira poderosa para avançar e voltar no vasto conjunto de recursos interligados chamado de Web.
A API de histórico da HTML5 é uma maneira padronizada para manipular o histórico do navegador via script. Parte desta API — navegando pelo histórico — está disponível em versões anteriores do HTML. As novas funcionalidades em HTML5 incluem uma maneira de adicionar entradas ao histórico do navegador, para visivelmente alterar a URL na barra de endereços do navegador (sem precisar atualizar a página), e um evento é acionado quando estas entradas são removidas da pilha do navegador quando o usuário pressiona o botão voltar. Isto quer dizer que a URL na barra de endereços do navegador pode continuar seu trabalho de ser um identificador único para o recurso atual, mesmo em aplicações com scripts pesados que nem sempre necessitam de uma atualização na página toda.
❧
Por que você iria manipular manualmente a barra de endereços do navegador? Afinal, um simples link pode navegar até uma nova URL; essa é a forma que a web tem funcionado nos últimos 20 anos. E isso vai continuar funcionando desta forma. Esta API não tenta revolucionar a web. Muito pelo contrário. Nos últimos anos, os desenvolvedores web têm encontrado novas e excitantes formas de revolucionar a web sem a ajuda de padrões emergentes. A API de histórico da HTML5 foi na verdade criada para garantir que as URLs continuem sendo úteis em aplicações web com scripts pesados.
Voltando aos princípios, o que uma URL faz? Ela identifica um recurso único. Você pode fazer um link direto para ela; você pode marcá-la; motores de busca podem indexá-la; você pode copiar, colar e enviá-la por e-mail para outra pessoa, esta pessoa pode clicar e acabar vendo o mesmo recurso que você viu originalmente. Estas são todas qualidades excelentes. URLs são importantes.
Então nos queremos que recursos únicos tenham URLs únicas. Mas ao mesmo tempo, navegadores sempre tiveram uma limitação fundamental: Se você mudar a URL, mesmo através de script, ele dispara uma requisição ao servidor web remoto e recarrega toda a página. Isso consome tempo e recursos, e parece um desperdício quando você esta navegando para uma página que é substancialmente semelhante à sua página atual. Tudo que possui na nova página é baixado, até mesmo as partes que são exatamente as mesmas da página atual. Não tem como alterar a URL em um navegador e este fazer download de apenas metade da página.
A API de histórico do HTML5 permite que você faça isso. Ao invés de desencadear uma atualização na página inteira, você pode utilizar o script para, em essência, baixar metade de uma página. Esta ilusão é um truque difícil, e requer algum trabalho da sua parte. Você está prestando atenção?
Digamos que você possui duas páginas, página A e página B. As duas páginas são 90% idênticas; somente 10% do conteúdo destas páginas é diferente. O usuário navega para a página A, então tenta navegar para a página B. Mas ao invés de desencadear uma atualização na página toda, você interrompe o navegador e segue estes passos manualmente:
XMLHttpRequest
). Isso
vai exigir algumas modificações no lado servidor de sua aplicação web.
Você vai precisar escrever um código que retorne apenas os 10% da página
B que é diferente da página A. Isso pode ser uma URL oculta
ou um parâmetro de consulta que o usuário final normalmente não vê.
innerHTML
ou outro método DOM). Talvez você
precise redefinir os manipuladores de eventos que foram alterados junto
com o conteúdo.
Ao final desta ilusão (se você a executar corretamente), o navegador acaba com um DOM que é idêntico a página B, como se você tivesse navegado diretamente para a página B. A barra de endereços do navegador acaba ficando com uma URL que é idêntica a da página B, como se você tivesse navegado diretamente para a página B. Mas na verdade você nunca navegou até a página B, e você nunca precisou atualizar toda a página. Esta é a ilusão. Mas porque a página "compilada" se parece exatamente como a página B e possui a mesma URL, o usuário provavelmente nunca notará a diferença (nem te agradecerá por todo trabalho pesado micro gerenciando suas experiências).
❧
A API de histórico do HTML5 é apenas vários
métodos no objeto window.history
, mais um evento no objeto
window
. Você pode utilizar isto para
detectar o suporte da API de histórico. O suporte atualmente é limitado para as últimas versões de alguns
navegadores, colocando essa técnica diretamente no campo "progressive
enhancement".
IE | Firefox | Safari | Chrome | Opera | iPhone | Android |
---|---|---|---|---|---|---|
· | 4.0+ | 5.0+ | 8.0+ | 11.50+ | 4.2.1+ | · |
dive into dogs é um exemplo simples, mas não trivial de usar a API de histórico do HTML5. Ele demonstra um padrão comum: um longo artigo com uma galeria de fotos. Em um navegador compatível, navegando pelos links "Próximo" e "Anterior" na galeria de fotos irá atualizar apenas foto no lugar e atualizará o URL na barra de endereços do navegador, sem desencadear uma atualização na página inteira. Em navegadores sem suporte - ou, de fato, navegadores compatíveis onde o usuário tenha desabilitado scripts - os links simplesmente funcionam como links normais, levando você a uma nova página com uma atualização na página toda.
Isso nos leva a um ponto importante:
Se sua aplicação web falhar em navegadores com script desabilitado, o cachorro de Jakob Nielsen vai até a sua casa e defecará no seu carpete.
Vamos dar uma olhada no exemplo dive into dogs e ver como ele funciona. Esta é a marcação relevante para uma única foto:
↶ O penhor
<aside id="gallery">
<p class="photonav">
<a id="photonext" href="casey.html">Next ></a>
<a id="photoprev" href="adagio.html">< Previous</a>
</p>
<figure id="photo">
<img id="photoimg" src="gallery/1972-fer-500.jpg"
alt="Fer" width="500" height="375">
<figcaption>Fer, 1972</figcaption>
</figure>
</aside>
Nada diferente aqui. A foto em si é uma <img>
dentro de
uma <figure>
, o link é um elemento
<a>
normal, e a coisa toda está colocada dentro de um
<aside>
. É importante que estes links regulares
realmente funcionem. Todo o código se passa atrás de um
script de detecção. Se um usuário
estiver utilizando um navegador sem suporte, nada do nosso código chique
da API de histórico será executado. E, claro, sempre há
alguns usuários com o script desativado por completo.
A função principal pega cada um destes links e repassa para uma função,
addClicker()
, que faz todo o trabalho de criação e
customização do click
.
function setupHistoryClicks() {
addClicker(document.getElementById("photonext"));
addClicker(document.getElementById("photoprev"));
}
Esta é a função addClicker()
. Ela pega um elemento
<a>
e adiciona um click
manipulado. E é
neste click
manipulado onde as coisas ficam interessantes.
function addClicker(link) {
link.addEventListener("click", function(e) {
swapPhoto(link.href);
history.pushState(null, null, link.href);
e.preventDefault();
}, false);
}
↜ Interessante
A função swapPhoto()
realiza as duas primeiras etapas de
nossa ilusão de três etapas. A primeira metade da
função swapPhoto()
faz parte da URL do link de
navegação em si — casey.html
, adagio.html
,
&c. — e constrói uma URL para uma página oculta
que contém nada mais que a marcação exigida pela próxima foto.
function swapPhoto(href) {
var req = new XMLHttpRequest();
req.open("GET",
"https://diveintohtml5.com.br/examples/history/gallery/" +
href.split("/").pop(),
false);
req.send(null);
Aqui temos um exemplo de marcação retornado por
https://diveintohtml5.com.br/examples/history/gallery/casey.html
. (Você pode verificar isso no seu navegador visitando a
URL diretamente.)
<p class="photonav">
<a id="photonext" href="brandy.html">Next ></a>
<a id="photoprev" href="fer.html">< Previous</a>
</p>
<figure id="photo">
<img id="photoimg" src="gallery/1984-casey-500.jpg"
alt="Casey" width="500" height="375">
<figcaption>Casey, 1984</figcaption>
</figure>
Isso lhe parece familiar? Deveria. Este é a mesma marcação básica utilizada na página original para mostrar a primeira foto.
A segunda metade da função swapPhoto()
realiza a segunda
etapa de nossa ilusão de três etapas: inserindo a
nova marcação baixada dentro da página atual. Lembre-se que tínhamos um
<aside>
envolvendo todo a figura, foto e legenda. Então
inserindo a nova marcação da foto é uma linha, atribuindo a propriedade
innerHTML
do <aside>
para a propriedade
responseText
retornada do XMLHttpRequest
.
if (req.status == 200) {
document.getElementById("gallery").innerHTML = req.responseText;
setupHistoryClicks();
return true;
}
return false;
}
(Observe também a chamada para o setupHistoryClicks()
. Isto é
necessário para reiniciar os eventos do click
manipulados nos
novos links de navegação. Atribuindo innerHTML
remove
qualquer traço dos links antigos e seus eventos.)
Agora, vamos voltar para a função addClicker()
. Depois de
alterar a foto com sucesso, temos mais uma etapa para a nossa
ilusão de três etapas: atribuir a
URL na barra de navegação do navegador sem atualizar a
página.
↶ A troca
history.pushState(null, null, link.href);
A função history.pushState()
recebe três parâmetros:
state
pode ser qualquer dado com estrutura
JSON. Isso é passado de volta para o manipulador do evento
popstate
, o qual você irá aprender em algum momento. Nós
não precisamos acompanhar nenhum estado nesta demonstração, isto será
mantido como null
.
title
pode ser qualquer string. Este parâmetro não é
utilizado atualmente pelos principais navegadores. Se você quiser
alterar o título da página, você deve armazenar isto em um argumento
state
e atribuir isto manualmente no callback do seu
popstate
.
url
pode ser, bem, qualquer URL. Isto é a
URL que você gostaria que aparecesse na barra de endereços
do navegador.
Ao chamar history.pushState
mudará imediatamente a
URL na barra de endereços do navegador. Então, este é o final
da ilusão? Bom, não exatamente. Nós ainda precisamos falar sobre o que
acontece quando o usuário pressiona o importantíssimo botão de voltar.
Geralmente quando um usuário navega a uma nova página (com uma atualização
de página inteira), o navegador joga a nova URL para a lista
de histórico, faz os downloads e desenha a nova página. Quando o usuário
pressiona o botão voltar, o navegador joga uma página para fora da pilha
de histórico e redesenha a página anterior. Mas o que acontece agora que
você gerou um curto-circuito de navegação para evitar a atualização da
página toda? Bom, você fingiu o "avançar" para uma nova URL,
então agora você pode também fingir um "voltar" para a
URL anterior. E a chave para forjar este "retorno" é o evento
popstate
.
↶ O prestígio
window.addEventListener("popstate", function(e) {
swapPhoto(location.pathname);
}
Após você ter utilizado a função history.pushState()
para
jogar a URL para o histórico do navegador, quando o usuário
pressionar o botão voltar, o navegador irá disparar um evento
popstate
no objeto window
. Esta é a sua chance
de completar a ilusão de uma vez por todas. Porque fazer alguma coisa
desaparecer não é o suficiente; você tem que trazer ela de volta.
Nesta demonstração, “trazer de volta” é tão simples quanto trocando a foto
original, que nós fazemos ao chamar o swapPhoto()
com a
localização atual. Quando o retorno do popstate
é chamado, a
URL visível na barra de endereço do navegador foi trocada
pela URL antiga. E também, a propriedade
location
global já foi atualizada com a antiga
URL.
Para ajudar a visualizar isso, vamos percorrer a ilusão inteira desde do começo ao fim:
https://diveintohtml5.com.br/examples/history/fer.html
, vê a história e a foto de Fer.
<a>
que
tem uma propriedade href
para
https://diveintohtml5.com.br/examples/history/casey.html
.
https://diveintohtml5.com.br/examples/history/casey.html
com uma atualização completa na página, o evento
click
manipulado dentro do elemento
<a>
executa seu próprio código.
click
manipulado chama a função
swapPhoto()
, que cria um objeto
XMLHttpRequest
para baixar o fragmento de código
HTML localizado em
https://diveintohtml5.com.br/examples/history/gallery/casey.html
.
swapPhoto()
atribui a propriedade
innerHTML
para o que envolve a galeria de foto (um elemento
<aside>
), substituindo assim a foto e a legenda de
Fer pela foto e legenda de Casey.
click
manipulado chama a função
history.pushState()
para manualmente alterar a
URL na barra de endereços do navegador para
https://diveintohtml5.com.br/examples/history/casey.html
.
history.pushState()
). Ao
invés de navegar para a URL anterior e redesenhar a página
toda, o navegador simplesmente atualiza a barra de endereço para a
URL antiga (https://diveintohtml5.com.br/examples/history/fer.html
) e executa um evento popstate
.
popstate
customizado manipula chamadas para a função
swapPhoto()
novamente, desta vez com a
URL antiga que agora já esta visível na barra de endereços
do navegador.
XMLHttpRequest
, a função
swapPhoto()
baixa o fragmento de
HTML localizado em
https://diveintohtml5.com.br/examples/history/gallery/fer.html
e atribui a propriedade innerHTML
do elemento
<aside>
, substituindo assim a foto e a legenda de
Casey com uma foto e legenda de Fer.
A ilusão está completa. Todas as evidências visíveis (o conteúdo da página e a URL na barra de endereços) sugerem ao usuário que ele navegou uma página a frente e uma para trás. Mas nenhuma página foi completamente atualizada - isto foi tudo uma ilusão meticulosamente executada.
❧
❧
Este foi “Manipulando Histórico Para Diversão & Lucro” O Sumário tem muito mais, se você quiser continuar a leitura.
Em associação a Google Press, O’Reilly está distribuindo este livro em variados formatos, incluindo papel, ePub, Mobi, DRM-free e PDF. A edição paga é chamada “HTML5: Up & Running,” e está disponível agora.
Se você gostou dessa introdução e quer mostrar como apreciou, basta comprar o livro “HTML5: Up & Running” com esse link afiliado ou comprar a edição eletrônica diretamente da O’Reilly. Você vai ganhar um livro, e eu vou ganhar um trocado. Atualmente não aceito doações diretas.
Copyright MMIX–MMXI Mark Pilgrim