Versão Impressão

HTML5

Um guia de referência para os desenvolvedores web.

16. DOM e HTML5

DOM e HTML5

O Modelo de Objetos do Documento (DOM, na sigla em inglês) é a interface entre a linguagem Javascript e os objetos do HTML. DOM é o método padrão para construção de aplicações ricas com Javascript e é amplamente conhecido e utilizado. Neste capítulo, supondo que você já conhece DOM para HTML 4 ou XHTML, vamos nos focar na diferença entre as versões anteriores do DOM e a do HTML 5.

Por quê DOM?

Os primeiros navegadores a incorporar um motor de Javascript tinham alert, prompt, document.write e mais meia dúzia de maneiras de se interagir com o usuário. E só. A idéia de acessar a árvore de objetos do HTML trouxe poder às interfaces com o usuário na web. A idéia era tão boa que os fabricantes de navegadores não puderam esperar até que tivéssemos uma especificação padrão que atendesse suas necessidades, e criaram cada um seu próprio método de resolver o problema. Isso resultou em anos e anos de incompatibilidade, em que era preciso escrever uma versão de seus scripts para cada navegador.

Queremos, com certeza, evitar uma nova guerra de padrões. Por isso recomendamos a você, por mais sedutor que pareça utilizar um recurso proprietário Javascript, que se atenha ao DOM.

Vamos às diferenças

getElementsByClassName

Esse é um sonho antigo de todo desenvolvedor Javascript. Com HTML5 você pode fazer:

destaques = document.getElementsByClassName('destaque')

E isso retornará todos os elementos do HTML que possuem a classe "destaque".

innerHTML

Outro sonho antigo que se torna realidade. A propriedade innerHTML é uma idéia tão boa que todos os navegadores atuais já a suportam há muito tempo e todo desenvolvedor web sabe usá-la. Apesar disso, ela nunca havia sido descrita como um padrão.

Se porventura você nunca viu a propriedade innerHTML em ação (puxa, onde você estava nos últimos dez anos?) saiba que ela contém uma string, o conteúdo HTML da página. E você tem acesso de leitura e escrita a essa propriedade.

Veja um exemplo de innerHTML:

function adicionaItem(nome){
  document.getElementById('lista').innerHTML += '<li>'+nome+'</li>'
}

activeElement e hasFocus()

O documento HTML5 tem uma nova propriedade, activeElement, que contém o elemento que possui o foco no momento. O documento também possui o método hasFocus(), que retorna true se o documento contém o foco. Seu usuário pode estar trabalhando com múltiplas janelas, abas, frames, ou mesmo ter alternado para outro aplicativo deixando o navegador com sua aplicação Javascript rodando em segundo plano. O método hasFocus() é uma conveniente maneira de tratar ações que dependem do foco na aplicação atual.

Veja um exemplo de script dependente de foco:

Arquivo: exemplos/16/focusNotify.html

1 <!DOCTYPE html>
2 <html lang="pt-BR">
3 <head>
4 <meta charset="UTF-8" />
5 <title>Notifier</title>
6 <script>
7
8   function notify(text){
9     document.getElementById('msg').innerHTML+='<p>'+text+'</p>'
10     titleFlick()
11   }
12
13   function titleFlick(){
14     if(document.hasFocus()){
15       document.title='Notifier'
16       return
17     }
18     document.title=document.title=='Notifier'?'* Notifier':'Notifier'
19     setTimeout('titleFlick()',500)
20   }
21
22   </script>
23 </head>
24
25 <body>
26 <input type="button" id="notify" value="Notify in 5 seconds"
27 onclick="notify('Will notify in 5 seconds...');setTimeout('notify(\'Event shoot!\')',5000)" />
28 <div id="msg"></div>
29 </body>
30
31 </html>

getSelection()

Os objetos document e window possuem um método getSelection(), que retorna a seleção atual, um objeto da classe Selection. A seleção tem, entre outros, os seguintes métodos e propriedades:

anchorNode
O elemento que contém o início da seleção
focusNode
O elemento que contém o final da seleção
selectAllChildern(parentNode)
Seleciona todos os filhos de parentNode
deleteFromDocument()
Remove a seleção do documento
rangeCount
A quantidade de intervalos na seleção
getRangeAt(index)
Retorna o intervalo na posição index
addRange(range)
Adiciona um intervalo à seleção
removeRange(range)
Remove um intervalo da seleção

Intervalos de seleção

Você deve ter notado acima que uma seleção é um conjunto de intervalos, da classe Range. Cada intervalo possui, entre outros, os seguintes métodos e propriedades:

deleteContent()
Remove o conteúdo do intervalo
setStart(parent,offset)
Seta o início do intervalo para o caractere na posição offset dentro do elemento DOM parent
setEnd(parent,offset)
Seta o final do intervalo para o caractere na posição offset dentro do elemento DOM parent

Tanto os objetos Selection quanto os objetos Range retornam o texto da seleção quando convertidos para strings.

document.head

O objeto document já possuía uma propriedade body, uma maneira conveniente de acessar o elemento body do HTML. Agora ele ganhou uma propriedade head, maneira também muito conveniente de acessar o elemento head.

Selector API

A Selector API não é novidade do HTML5, é anterior a ele. Mas como ainda é desconhecida de parte dos desenvolvedores, convém dizer que ela existe, e que continua funcionando no HTML5. Com a selector API você pode usar seletores CSS para encontrar elementos DOM.

A Selector API expõe duas funções em cada um dos elementos DOM: querySelector e querySelectorAll. Ambas recebem como argumento uma string com um seletor CSS. A consulta é sempre feita na subtree do elemento DOM a partir do qual a chamada foi disparada. A querySelector retorna o primeiro elemento que satisfaz o seletor, ou null caso não haja nenhum. A querySelectorAll retorna a lista de elementos que satisfazem o seletor.

Veja, neste exemplo, um script para tabelas zebradas com Selector API:

Arquivo: exemplos/16/zebra.html

1 <!DOCTYPE html>
2 <html lang="pt-BR">
3 <head>
4 <meta charset="UTF-8" />
5 <title>Zebra</title>
6 <style>
7   .zebraon{background:silver}
8 </style>
9 <script>
10 window.onload=function(){
11   var zebrar=document.querySelectorAll('.zebra tbody tr')
12   for(var i=0;i<zebrar.length;i+=2)
13     zebrar[i].className='zebraon'
14 }
15 </script>
16 </head>
17
18 <body>
19 <table class="zebra">
20 <thead><tr>
21 <th>Vendedor</th> <th>Total</th>
22 </tr></thead>
23 <tbody><tr>
24 <td>Manoel</td> <td>12.300,00</td>
25 </tr><tr>
26 <td>Joaquim</td> <td>21.300,00</td>
27 </tr><tr>
28 <td>Maria</td> <td>13.200,00</td>
29 </tr><tr>
30 <td>Marta</td> <td>32.100,00</td>
31 </tr><tr>
32 <td>Antonio</td> <td>23.100,00</td>
33 </tr><tr>
34 <td>Pedro</td> <td>31.200,00</td>
35 </tr></tbody>
36 </table>
37 </body>
38 </html>

Características especiais de DomNodeList

As listas de elementos retornadas pelos métodos do DOM não são Arrays comuns, são objetos DomNodeList, o que significa que, entre outros métodos especiais, você pode usar list[0] ou list(0) para obter um elemento da lista. Também pode usar list["name"] ou list("name") para obter um objeto por seu nome. Duas adições interessantes do HTML5 ao usar este último método:

  1. O objeto é buscado pelos atributos name ou id.
  2. Uma lista de campos de formulário com o mesmo valor no atributo name (uma lista de radio buttons, por exemplo) será retornada caso mais de um objeto seja encontrado. Essa lista contém um atributo especial, value, muito conveniente. Ele contém o valor do radio marcado e, ao ser setado, marca o radio correspondente.

Datasets

Você pode atribuir dados arbitrários a um elemento HTML qualquer, prefixando seus atributos com "data-". Por exemplo:

<img src="computador1.jpg" alt="Novo GNexius Forethinker" id="c1"
  data-processor="35Ghz" data-memory="48GB" 
  data-harddrive="16TB" data-screen='45"' >

Você pode acessar esses valores via Javascript, através do atributo dataset, assim:

var img=document.getElementById('c1')
proc=img.dataset.processor

As propriedades de dataset têm permissão de leitura e escrita.