Autor: Elcio Ferreira
Fonte: www.elcio.com.br
----------------------------
A Guerra dos Browsers Acabou
Se você aprendeu (ou tentou aprender) DHTML há algum tempo, na época da guerra entre Netscape 4 e Internet Explorer 4, tem boas razões para ter calafrios quando ouve falar no assunto. Era o início do DHTML, Microsoft e Netscape tinham criado sua própria versão do modelo de objetos para documentos HTML, o DOM, tornando um inferno a vida do desenvolvedor que pretendia desenvolver um script que funcionasse em ambos os navegadores.
Naquele tempo triste era muito comum que um script construído para um navegador dobrasse de tamanho ao ser adaptado para funcionar em ambos. E as documentações ganhavam volume com uma infinidade de linhas com "Tratamento de evento para o Internet Explorer" ou "Obtendo o Objeto para o Netscape". É claro, isso tinha que ter um fim.
E teve. A Guerra dos Browsers Acabou. E não foi a Microsoft que deu fim ao impasse, foram os padrões web. Tais padrões, criados pelo W3C, nos deram um ambiente comum, bastante semelhante em todos os navegadores atuais. Desde o Internet Explorer, em suas versões mais atuais (5 e 6), até o moderníssimo Opera 7, passando pelos navegadores baseados no engine Gecko: Netscape 6 e 7, Mozilla e Firebird, pelos navegadores dos gerenciadores de janela do Linux, Konkeror (KDE) e Galeon (Gnome), e incluindo o novíssimo Safari da Apple (baseado no engine KHTML, o mesmo do Konqueror) todos os navegadores atuais possuem considerável complacência aos padrões.
DHTML é a interação entre três tecnologias diferentes, HTML, CSS e javascript, através de uma interface conhecida como DOM (Document Object Model). Todos os navegadores hoje possuem boa complacência aos padrões definidos para o HTML e para o javascript, de modo que o desenvolvedor pode ter grande segurança dos resultados. Já em relação ao CSS, a maioria dos navegadores segue fielmente os padrões, exceto um: o Internet Explorer para Windows. Isso pode representar um problema se você precisa usar os recursos mais avançados da linguagem, mas não é nada que algum tempo estudando o assunto não resolva. Já em relação ao DOM, é preciso entender algo importante. Todos os navegadores hoje oferecem complacência mais que suficiente ao padrão do W3C para o DOM, mas a maioria, em especial a Microsoft, gosta de extender esse DOM adicionando funcionalidades e recursos proprietários. De maneira geral, tudo o que os recursos proprietários oferecem pode ser feito satisfatoriamente com o DOM padrão. Ou seja, você não perde nada em abandonar as extensões proprietárias ao DOM, e ganha significativa compatibilidade. Na prática isso vai trazer-nos apenas uma restrição: não use o material da Microsoft para aprender. Se você aprender as coisas do "jeito Microsoft" seus scripts vão funcionar apenas no Internet Explorer. Se aprender a fazer do "jeito W3C" vai produzir com a mesma eficiência e seus scripts vão funcionar em qualquer navegador. Simples assim.
O Que Você Precisa Saber
Este não é um tutorial de HTML, CSS ou javascript. Vamos falar do DOM, e de como ele é usado para integrar essas três linguagens. Por isso, é importante que você já as conheça, pelo menos superficialmente:
- HTML: você não precisa conhecer a fundo as peculiaridades das diferentes versões do HTML ou saber de cor a função de cada tag. Bastará, para acompanhar este material, uma noção básica da estrutura do HTML e de suas tags mais usadas.
- CSS: aqui também, você não precisa ser um especialista em layouts tableless ou conhecer a fundo o comportamento de cada atributo em cada navegador para entender os nossos exemplos. Bastará um conhecimento básico da linguagem, de sua estrutura, e dos seletores e atributos mais usados.
- java script: precisaremos de alguma fluência na linguagem. Entender o DOM é entender como programar com ele, por isso precisaremos que você seja fluente em javascript, senão muitos dos exemplos que seguirão podem não fazer sentido para você. Você não precisa conhecer os recursos mais avançados da linguagem, como tratamento de erros ou prototipagem, mas precisará ser fluente em javascript se quiser nos acompanhar. Fluência em ActionScript também serve.
- Orientação a Objeto: você vai precisar dos conceitos básicos: objeto, classe, método e propriedade. Isso já basta.
- Música: você não vai precisar de muita teoria, mas eu sugiro que aprenda a tocar algum instrumento. É um ótimo meio de relaxar quando estiver com a cabeça quente. Se me permite um palpite, a gaita de blues é um instrumento interessante, que você pode carregar no bolso para qualquer lugar. Só tome cuidado de não irritar seus colegas, e principalmente seu chefe.
O Bom, o Mal e o Sensato
Há um assunto sobre o qual preciso lhe dar algumas idéias antes de prosseguirmos: DHTML não é acessível a quem não tiver um browser moderno, e, dependendo de como você o projetou, a quem não possui as mesmas habilidades que você. Isso pode ter uma série de implicações indesejadas. Um deficiente visual usando um leitor de tela pode não conseguir entrar no site se você não fornecer um substituto para o menu DHTML. O Google pode não conseguir indexar suas páginas se seu robozinho não encontrar um link comum para elas (o que pode acontecer se você, por exemplo, criou um esquema de navegação esotérico com DHTML.)
Por isso ao criar scripts DHTML você precisa analisar seu impacto sobre a acessibilidade e indexabilidade da página. De maneira geral não é complexo adaptar o script ou oferecer alternativas para que o site se mantenha acessível. Mas não há regras aqui, cada caso é um caso e a decisão é sempre sua. De maneira geral é bom construir seus scripts de maneira que seu site ou aplicação continue acessível se eles falharem, e é bom também testar o site em um navegador sem javascript, pois é assim que o Googlebot, por exemplo, vai vê-lo.
Mil maneiras
Existe mais de uma maneira certa de fazer cada coisa, e, é claro, infinitas maneiras erradas. Vou me contentar em explicar aqui apenas uma maneira certa de fazer cada coisa. É mais do que suficiente para trabalhar direito. Se você quiser saber tudo o que está escrito nas especificações, então leia as especificações. Por exemplo, o objeto history contém o método go que recebe um parâmetro numérico para avançar ou retroceder no histórico. Assim, history.go(-1) retrocede e history.go(1) avança. O objeto history tem também o método back para voltar e o forward para avançar. Então, como não pretendo escrever uma referência, vou falar aqui apenas do método go, que te permite fazer tudo. Isso é essencial para que você consiga chegar ao fim da leitura sem dormir.
Localizando
A primeira coisa que precisamos fazer é entender o que é o DOM. Ele na verdade é um padrão de interface para que o javascript (e outras linguagens) possa acessar o HTML e o CSS. Também há uma versão do DOM para XML, mas isto está fora do nosso escopo. É porém conveniente saber que, embora o DOM para XML possua diferenças de sua implementação para HTML, muito do conhecimento obtido aqui será útil se você tiver que trabalhar com XML.
O DOM é portanto uma interface para a estrutura HTML+CSS, com uma representação de cada objeto na estrutura. Vamos a um exemplo. Tomemos o código:
CODE
<b><html></b>
<b><head></b>
<b><title></b>Título do Documento.<b></title></b>
<b></head></b>
<b><body></b>
<b><h1></b>Título<b></h1></b>
<b><p></b>Texto, texto, texto, <b><b></b>texto<b></b></b>...<b></p></b>
<b></body></b>
<b></html</b>>
Ao exibir esse documento o navegador vai criar na memória uma estrutura hierárquica (em formato de árvore) com representações de cada objeto exibido. Essa estrutura inicia-se com o objeto window, que representa a própria janela aberta do navegador. Cada navegador tem pequenas particularidades ao montar os detalhes dessa estrutura, mas de maneira geral podemos nos ater ao que eles tem em comum. O documento acima quando exibido pelo navegador deve gerar a seguinte estrutura:
- window: a janela do navegador ou frame onde o documento é carregado.
- opener: se é uma janela popup, opener aponta para a janela que a abriu.
- parent: se é um frame, parent aponta para o frame ou janela pai, aquele que contém o frameset que carrega esta página.
- frames: aponta para uma coleção se houverem frames no documento. No nosso caso não há.
- location: um objeto que gerencia a URL da janela atual. Possue entre outros os métodos reload e replace.
- history: um objeto que gerencia o histórico da janela atual. Possue entre outros os métodos back e forward.
- document: representa o documento HTML aberto. É aqui que começa de fato o nosso interesse.
- title: O título do documento.
- body: Representa a tag body, considerada a tag base para o acesso ao conteúdo do documento.
- childNode 0: O elemento h1 no documento acima, primeiro filho do body.
- childNode 1: O elemento p, segundo filho de body. Esse elemento também possui um filho:
- childNode 0: O elemento b dentro do p.
Essa estrutura está bastante simplificada. Cada um desses elementos tem mais propriedades e métodos. Mas por hora basta que você entenda que os elementos são representados numa árvore como mostrado acima, começando no elemento window.
Vamos a um pequeno exemplo?
A primeira coisa a saber é que o nível default no javascript é o nível do objeto window. Inclusive as funções e variáveis que você cria em seus scripts se tornam filhas do objeto window. Por isso, se uma janela possui uma função chamada calculaDados() e ela abre um popup, podemos chamar, de dentro do popup:
CODE
opener.calculaDados()
Opener, você se lembra, refere-se à janela mãe, aquela que abriu o popup. Segundo a mesma lógica, tanto faz escrever:
CODE
alert("123")
document.write("456")
open("novo.html")
close()
ou:
CODE
window.alert("123")
window.document.write("456")
window.open("novo.html")
window.close()
E se você criou uma função chamada minhaFuncaoTeste(), tanto faz chamá-la com:
CODE
minhaFuncaoTeste()
ou
CODE
window.minhaFuncaoTeste()
Então, seguindo a árvore do DOM, para chegar até o objeto H1, podemos usar:
CODE
document.body.childNodes[0]
Usamos document porque o nível default é window, lembra? Poderíamos ter escrito window.document, mas é desnecessário. Veja como usar a linha acima com a propriedade innerHTML para obter o conteúdo da tag h1 no
exemplo 1. É um exemplo bem simples e não deve representar nenhuma dificuldade para você.
Na verdade esse é apenas um dos métodos, muito pouco usado, para se acessar um elemento no DOM. Veremos a seguir métodos muito mais práticos e populares.
Rastreamento Via Satélite
Há um método para se acessar elementos do HTML que é de longe o mais usado, e é também o mais simples de todos. Trata-se do método getElementById, disponível no objeto document. Lembra-se de que, ao estudar CSS, você aprendeu que podem haver diversos elementos com a mesma classe, mas só pode haver um elemento de cada id no documento (o quê? Nunca estudou CSS? Você não sabe o que está perdendo.) Pois bem, esse id único serve para que você possa acessar via javascript exatamente aquele elemento. Uma breve olhada no
exemplo 2 deve elucidar o assunto.
Aqui está o segredo da simplicidade. O método getElementById está disponível no Internet Explorer desde a versão 5.0. Mas os desenvolvedores, acostumados com a collection proprietária document.all, não se importaram muito com isso. No velho Netscape 4 havia ainda uma outra collection, document.layers. A lei é: esqueça essa baboseira toda e use document.getElementById sempre. Boa parte dos scripts já existentes vão se tornar crossbrowser se você simplesmente fizer isso.
Os Cães Farejadores
Há ainda um outro método para acessar os elementos do HTML que vale a pena conhecer. É o método getElementsByTagName, do objeto document. Esse método recebe uma string com um nome de tag e retorna um Array com todas as tags daquele tipo. Por exemplo:
CODE
paragrafos=document.getElementsByTagName("p")
Essa linha armazena na variável
paragrafos um Array com todas as tags
p do documento. Imagine agora que queiramos, por exemplo, colocar uma borda vermelha em todos os parágrafos do documento. Podemos usar:
CODE
paragrafos=document.getElementsByTagName("p")
for(var x=0;x<paragrafos.length;x++)
paragrafos[x].style.border="1px solid red"
Você pode ver esse código funcionando no
exemplo 3. Agora vamos complicar um pouco mais. Teremos alguns parágrafos com a classe css "maior". Queremos colocar borda apenas nesses. É na verdade muito simples:
CODE
paragrafos=document.getElementsByTagName("p")
for(var x=0;x<paragrafos.length;x++)
<b>if(paragrafos[x].className=="maior")</b>
paragrafos[x].style.border="1px solid red"
O atributo className contém o nome da classe CSS do elemento. Assim, com esse comando if, selecionamos apenas os parágrafos cuja classe é "maior". Veja isso funcionando na prática no
exemplo 4.
Esse é apenas um exemplo de como usar um atributo para filtrar um Array de elementos. Além do atributo className há uma série de outros que são padrão e podem ser utilizados. Segue a lista dos mais comuns:
- attributes - um Array com todos os atributos HTML da tag. Cada elemento do Array é um objeto com as propriedades name e value. O Array pode ser acessado por índice numérico ou pelo nome do atributo. Assim: elemento.attributes["align"].value retorna o valor do atributo HTML align da tag selecionada.
- childNodes - já demos uma olhada nesse. É uma coleção de todos os nós filhos do atual.
- className - também já vimos esse, é o nome da classe css do elemento.
- offsetWidth e offsetHeight - altura e largura real do elemento na tela.
- offsetTop e offsetLeft - posição real do elemento na tela.
- id - sem segredo, o id do elemento.
- innerHTML - o código HTML dentro do elemento.
- nodeName e tagName - retornam a mesma coisa, o nome da tag do elemento (por exemplo: "H1" ou "BR").
- parentNode - elemento pai, aquele que contém o elemento atual.
- title - valor do atributo title do elemento.
A lista acima pode ser usada em praticamente qualquer elemento HTML e cobre quase todas as situações desejáveis num script DHTML. Ou seja, existe muito mais do que isso, mas sabendo apenas essa lista você dificilmente sentirá falta de algo.
Maquiagem
Veja bem, o jeito correto de se construir páginas web hoje é usar o HTML para estruturar seu conteúdo e formatá-lo via CSS. Se você não conhece bem CSS, já está alguns anos atrasado. É hora de correr atrás do prejuízo.
Ascensão Social
Um grande truque para se alterar a aparência de um elemento é modificar seu className. Basta que se criem duas classes CSS com os estilos que se quer alternar entre os elementos. Vamos a um exemplo simples:
CODE
<style type="text/css">
input.normal{
border:1px solid black;
background:#FFC;
color:navy;
}
input.comfoco{
border:1px solid red;
background:navy;
color:#FFC;
}
</style>
.
.
.
<input type="text" class="normal"
onfocus="this.className='comfoco'"
onblur="this.className='normal'">
Você pode ver esse código funcionando no
exemplo 5. Como você pode ver, há muito pouco javascript ali e não será difícil adaptá-lo.
Cirurgia Plástica
Outro meio muito utilizado para se alterar a aparência de um elemento é a propriedade style. Essa propriedade é um objeto da classe CSSStyleDeclaration. Ele contém um membro para cada atributo CSS disponível no navegador.
A regra é muito simples: atributos de nome simples, como padding, mantém seu nome. Assim, para alterar o padding de determinado elemento usamos:
CODE
elemento.style.padding="20px"
Já se o atributo desejado é formado por mais de uma palavra, como padding-top, remove-se o hífen e transformando a inicial da segunda palavra em maiúscula. Assim, para alterar o padding-top de um elemento usamos:
CODE
elemento.style.paddingTop="50px"
Os valores dos atributos são sempre string. Não se esqueça de passar as unidades de medida. Passar "20" para um atributo pode ter efeitos diferentes em diferentes navegadores (inclusive efeito nenhum). Já "20px" serão 20 pixels em todos.
Como todos os atributos CSS estão disponíveis para alteração individual, esse método proporciona grande flexibilidade, como você pode ver no
exemplo 7.
Atacando na Raiz
Talvez você esteja pensando em uma mudança mais radical. Nada de mudar o estilo de um elemento ou outro, você quer mudar o layout do site inteiro. Ok, não há problemas aqui também. Você pode selecionar e alterar diretamente os elementos link e style que fazem referência ao seu CSS.
Para obter uma referência ao elemento desejado você pode usar o método getElementsByTagName do objeto document ou pode colocar um id no elemento e usar o getElementById. Embora pareça haver uma preferência geral pelo primeiro método, eu prefiro o segundo que não me obriga a fazer malabarismos com o Array resultante para encontrar o elemento certo.
Elementos link e style não são elementos comuns do HTML, logo não têm disponíveis todas as propriedades e métodos que você usaria, por exemplo, para alterar um parágrafo de texto. Uma vez encontrado o elemento, há dois métodos para modificá-lo. O primeiro, mais comum, funciona com ambos os tipos de elementos, é a propriedade disabled. Atribuindo o valor true a disabled você desativa a folha de estilos. Atribuindo false você a reativa.
Um método muito usado para se criar style switchers é colocar várias folhas de estilo em uma página e criar um script para habilitar apenas uma delas. Você pode ver um script de style switcher bem simples no
exemplo 8. Acrescente algumas linhas para gravar um cookie com as preferências do usuário e você terá um completíssimo style switcher. O segundo método não pode ser usado em objetos style, apenas link. Consiste em trocar o atributo href do link, fazendo-o apontar para outro arquivo CSS. Tem como vantagem a simplicidade do script e o fato de o usuário não fazer o download de todas as folhas de estilo se não for usá-las. A desvantagem é que, ao acionar a mudança, o browser ainda vai fazer o download do arquivo CSS, criando um pequeno delay entre o clicar no link e o exibir do layout.
A técnica oferece porém a flexibilidade de trabalhar via script a URL do CSS a ser carregado. Uma pequena demonstração do que pode ser feito você encontra no
exemplo 9. Você deve notar que, embora todos os nossos exemplos aqui trabalhem com apenas uma folha de estilo de cada vez, você pode trabalhar com mais de uma folha de estilo habilitada, exibindo uma combinação delas.<script type="text/javascript" src="http://elcio.com.br/crossbrowser/adsensecrossbrowser.js?0"><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> <script type="text/javascript" src="http://elcio.com.br/adspy/adspy.php">
Conteúdo
Agora que sabemos como alterar a aparência de um elemento qualquer ou mesmo de toda a página através de DHTML, vamos passar a estudar como alterar o conteúdo de um elemento HTML. Aqui também não é necessário esgotarmos tudo o que há sobre o assunto, uma vez que os dois métodos de que falaremos cobrem a esmagadora maioria das situações.
HTML
O primeiro método que podemos usar para alterar o conteúdo de um elemento é o mais abrangente (e mais usado). Trata-se da propriedade innerHTML, que contém o código HTML interno ao elemento. Você pode lê-la e alterá-la. Assim, para trocar o conteúdo de um elemento qualquer usamos:
CODE
elemento.innerHTML="Novo conteúdo."
O valor de innerHTML é código HTML puro. Claro, como você já deve estar imaginando, pode criar novos elementos passando código HTML.
Veja um exemplo da propriedade innerHTML funcionando com um script que usa expressões regulares para ressaltar uma palavra no texto no
exemplo 10.
Tabela
Imagine o trabalho que pode gerar criar um script para alterar o conteúdo de uma tabela HTML extensa usando innerHTML. Por conta disso há uma série de métodos específicos para criação e alteração do conteúdo de tabelas. O objeto table por exemplo contém:
- rows - um Array de objetos TableRow, as linhas da tabela.
- width - propriedade que representa o atributo border da tag table.
- border - propriedade que representa o atributo border da tag table.
- cellPadding - propriedade que representa o atributo cellpadding da tag table.
- cellSpacing - propriedade que representa o atributo cellspacing da tag table.
- deleteRow - método que recebe um parâmetro, rowIndex, e exclui a linha especificada na tabela.
- insertRow - método que recebe um parâmetro, rowIndex, e insereuma linha acima da linha especificada na tabela. Retorna um objeto TableRow representando a linha inserida.
O objeto TableRow contém:
- cells - um Array de objetos TableCell, as células da tabela.
- deleteCell - método que recebe um parâmetro, index, e exclui a célula especificada.
- insertCell - método que recebe um parâmetro, index, e insere uma célula antes da especificada. Retorna um objeto TableCell representando a célula inserida.
- rowIndex - o índice desta linha na tabela.
O objeto TableCell contém:
- cellIndex - o índice desta célula na linha.
- align - propriedade que representa o atributo align da tag td ou tr.
- vAlign - propriedade que representa o atributo valign da tag td ou tr.
- colSpan - propriedade que representa o atributo colspan da tag td ou tr.
- rowSpan - propriedade que representa o atributo rowspan da tag td ou tr.
É claro, além desses membros especiais, cada um desses elementos ainda conta com as propriedades de todos os elementos html, como className e innerHTML. Você pode ver como usar as propriedades especiais das tabelas no
exemplo 11
Comportamento
Agora vamos tratar de algo essencial: responder às ações do usuário. Como você deve saber, uma ação que o usuário execute em qualquer objeto de uma página é chamada de "evento". Há duas maneiras de associar código a um evento. A primeira, mais simples e muito comum, é feita diretamente no HTML, assim:
CODE
<input type="button" value="Excluir" onclick="excluir()">
O código acima gera um botão que, quando recebe o evento click (ou seja, quando o botão é pressionado) executa a função javascript excluir().
Você provavelmente já viu código assim um milhão de vezes. É, em muitos aspectos, a maneira mais fácil de se capturar eventos em uma página simples. Há porém dois problemas básicos com o método que nos levam a querer aprender mais:
- Falta de flexibilidade: você não pode criar de maneira transparente um script que mude o comportamente de um objeto.
- Acoplamento: um dos objetivos dos Web Standards é que você possa manter separados conteúdo e estrutura (HTML), aparência (CSS) e comportamento (javascript). Além de ferir os modernos princípios do webdesign, ainda destrói qualquer encapsulamento, acoplando seu script ao seu HTML.
EventListeners
Há, é claro, uma maneira de se atribuir código a um evento em um objeto através de script, o que garante grande flexibilidade e evita o acoplamento. Não se iluda, simplesmente conhecer essa técnica não vai fazer automaticamente com que você desenvolva scripts com bom nível de encapsulamento. É preciso algum estudo e planejamento para isso. Por outro lado, não conhecer estes detalhes vai impedí-lo de realmente separar comportamento de conteúdo.
Vamos então ao que interessa. A recomendação do W3C sugere um método,
addEventListener, para se atribuir um handler a um evento qualquer. Isso funciona adequadamente em todos os navegadores atuais, exceto o Internet Explorer. Para este, a Microsoft inventou seu próprio jeitinho de fazer as coisas. Trata-se do método
attachEvent, que faz exatamente a mesma coisa do método proposto pelo W3C. Felizmente, é muito fácil criar uma função compatível com todos os navegadores:
CODE
function addEvent(obj, evType, fn){
if (obj.addEventListener)
obj.addEventListener(evType, fn, true)
if (obj.attachEvent)
obj.attachEvent("on"+evType, fn)
}
Essa função é uma simplificação da usada por
Simon Willison. Com ela você pode adicionar um handler de evento a um objeto de maneira simples, funcioando em qualquer navegador atual, como mostrado no
exemplo 12. No
exemplo 13 você pode ver como é simples separar conteúdo de comportamento. Se você remover a tag
<script> no começo do documento vai ter HTML puro, sem vestígios de qualquer DHTML.
Tratamento de Eventos
Basta agora entendermos como, numa função que recebe um evento, podemos entender qual foi o evento capturado e em que objeto ocorreu. Chamamos a isso de tratar o evento. Novamente, temos aqui uma diferença entre o que o Internet Explorer inventa e o padrão que o resto do mundo segue. Para qualquer navegador basta colocar um argumento na declaração de função que será handler e esse argumento receberá o evento (um objeto da classe
Event). No Internet Explorer o evento atualmente sendo tratado é armazenado em
window.event. Assim, na função de tratamento de evento ficamos com:
CODE
recebeClick(e){
if (typeof(e)=='undefined')var e=window.event
...
}
Basta isso para que em todos os navegadores a variável
e contenha o objeto
Event. Agora temos outro problema: a forma de capturar o alvo do evento (o objeto que recebeu o evento) também é diferento no Internet Explorer. Ficaremos com o seguinte:
CODE
recebeClick(e){
if(typeof(e)=='undefined')var e=window.event
source=e.target?e.target:e.srcElement
...
}
Agora está quase pronto. Temos ainda uma diferença na implementação, no Safari (olha só, não é o Internet Explorer quem está criando caso desta vez). Se o objeto que recebe o evento contiver texto, não sendo uma imagem ou campo de formulário, o source capturado será o texto dentro do objeto. Um HTMLNodeElement do tipo 3. Não sei quem foi o maluco que implementou isso, mas agora ficamos assim:
CODE
recebeClick(e){
if(typeof(e)=='undefined')var e=window.event
source=e.target?e.target:e.srcElement
if(source.nodeType == 3)source = source.parentNode
...
}
Você pode ver esse código funcionando no
exemplo 14 (função
foi()). Pode também ver algo mais complexo feito com isso no
exemplo 15 (função
sortThisTable()).
Está certo. Nesse capítulo o código começou a ficar mais complexo e tivemos que alterar um pouco o código para que funcionasse em todos os browsers. Mas faça as contas. Colocamos uma função a mais,
addEvent, no começo de cada script, e três linhas a mais em cada handler de evento. Nada realmente complicado.
Window, Document e etc.
Vamos ao feijão com arroz. É preciso entender o que podemos usar dos objetos window e document e de seus membros, para não ter surpresas desagradáveis com algum navegador. Não tenho aqui a pretensão de escrever uma referência a estes objetos. Há ótimas referências na web. Vou apenas mostrar exemplos das tarefas mais comuns em DHTML.
Novas janelas
Para abrir novas janelas do navegador, usamos o método open do objeto window, no formato:
CODE
window.open(endereco, nome, parametros)
Onde
endereco recebe o endereço da página a ser aberta,
nome recebe o nome da nova janela (assim páginas podem ser abertas nela usando o atributo
target dos links) e
parametros recebe uma lista de características da nova janela.
Se já houver uma janela aberta com o nome especificado, a página é carregada nesta janela. Se nenhum parâmetro for especificado, será aberta uma janela comum do navegador. Se for especificada a altura ou a largura sem nenhum outro parâmetro será aberta uma janela sem barras de ferramentas e barra de status. Os demais parâmetros você pode encontrar em qualquer boa referência de javascript.
Tamanho da tela
Há vários métodos disponíveis para calcular resolução de tela, tamanho da janela atual e do documento. O objeto window possui as propriedades
screenX e
screenY que retornam a posição da janela atual na tela. Aqui, mais uma vez, o Internet Explorer não segue o padrão, inventando seu próprio jeito de fazer as coisas. Felizmente, é muito fácil resolver o problema:
CODE
if(!window.screenX)screenX=screenLeft
if(!window.screenY)screenY=screenTop
O código acima cria as propriedades
screenX e
screenY no Internet Explorer.
O objeto window ainda possui um membro
screen, que possui os métodos
width e
height. Com isso é muito simples saber a resolução da tela. O que pode acontecer é que o Icq ou algum outro programa esteja reduzindo a área útil da tela. Para obter a área útil disponível para programas usamos os métodos
availWidth e
availHeight do objeto
screen.
Você também pode saber o tamanho da área de documento na janela atual usando os membros
offsetWidth e
offsetHeight de
document.body.
Histórico
Se você leu a
introdução, então já leu tudo o que eu tenho a dizer sobre o objeto
history. Ele é membro de
window e possui o utilíssimo método
go, que recebe um parâmetro numérico e faz retroceder ou avançar no histórico. Assim: history.go(-2) equivale a clicar no botão
voltar duas vezes.
Location
O objeto
location representa a localização atual, a URI em que você está navegando agora. Ele possui, entre outros, um membro
href, cujo valor é uma string com a URI atual, e um membro
reload, um método que recarrega a página atual.
Veja exemplos de uso dos objetos history e location no
exemplo 16.
Timeout e Interval
Nenhum segredo aqui. Se você aprendeu usar
setTimeout,
setInterval,
clearTimeout e
clearInterval em alguma referência para qualquer navegador, pode usar sem medo, funciona exatamente do mesmo jeito em todos, como você pode ver no
exemplo 17.
Formulários
Formulários são, provavelmente, o assunto que gera mais dúvidas em quem está aprendendo HTML. Não é diferente com javascript e DHTML. Basta porém um pouco de persistência no estudo e logo você estará dominando os métodos e propriedades de cada tipo de campo de formulário.
Encontrando
Nossa primeira tarefa é conseguir referenciar o formulário através de script. Para simplificar as coisas, há entre os diversos métodos de se referenciar um formulário, dois que eu gostaria de recomendar. O primeiro, o simples: document.nomedoformulario. Resolve boa parte das necessidades, uma vez que geralmente o formulário possui um atributo
name. Se você quiser acessar um formulário sem
name ou deseja trabalhar com todos os formulários da página (com um bloco
for por exemplo) pode usar o segundo método. O objeto
document conte um Array chamado
forms. Veja como usar o Array
forms no
exemplo 18.
O passo seguinte é encontrar os campos dentro do formulário. Aqui também nenhum segredo. Da mesma forma que com o formulário vou recomendar dois, dos inúmeros métodos possíveis. O primeiro é formulario.nomedocampo, simples e direto como você pode ver no
exemplo 19. O outro é usando o Array formulario.elements, como você pode ver no
exemplo 20.
Radio, checkbox e select
Raramente vejo alguém com problemas para acessar propriedades e métodos de campos
text,
password,
textarea,
button e etc. A grande maioria dos problemas acontece ao acessar objetos
select,
checkbox e
radio. Então vamos atacá-los um por um:
Select
A principal dificuldade de muitos desenvolvedores com o select é o fato de ele não possuir um atributo
value. A confusão é aumentada pelo fato de o Internet Explorer, ignorando as especificações, oferecer um atributo
value. Assim, muita gente programa objetoselect.value, testa apenas no Internet Explorer, e quando abre o site em outro navegador culpa o navegador pelo seu erro.
O objeto select contém dois membros fundamentais para acessarmos seu valor: o Array
options e a propriedade
selectedIndex. O Array
options contém os options do select e cada um deles possui duas propriedades:
value, que contém o valor do atributo HTML
value daquele option, e
text, que contém o texto da opção. O atributo
selectedIndex é um número, o índice da opção selecionada. Assim, para obter o valor de um select, usa-se:
CODE
objetoselect.options[objetoselect.selectedIndex].value
Como você pode ver no
exemplo 21. Claro, para descobrir os valores selecionados numa caixa de seleção múltipla você precisa varrer o Array de options, como no
exemplo 22. Outro problema de muitos desenvolvedores com selects é como criar novas opções dentro de um select. Para isso os navegadores provêem uma função, Option, constructor de um objeto option, com a seguinte sintaxe:
CODE
variavel=new Option(texto,valor)
Você pode ver o constructor
Option sendo usado no
exemplo 23. Já para remover uma opção de um select basta:
CODE
objetoselect.options[indice]=null
Você pode ver esse método sendo usado em uma aplicação bastante popular, no
exemplo 24.
Checkbox
Para saber se um checkbox está ou não marcado acessamos sua propriedade
checked. Podemos também alterá-la, como mostra o
exemplo 25. Se você tiver vários checkboxes com o mesmo nome eles podem ser acessados como um Array, como mostra o
exemplo 26.
Radio
Com objetos radio temos uma situação peculiar. Dificilmente alguém achará útil um único objeto radio. Eles sempre aparecem em grupos de objetos com o mesmo nome e podem ser acessados com facilidade como um Array, como mostra o
exemplo 27. Cada item do Array possui uma propriedade checked que funciona exatamente como no checkbox.
Erros comuns
Já vi tanta gente cometendo esses erros que resolvi avisar você:
Métodos são métodos, propriedades são propriedades
O código a seguir:
CODE
window.location.href("teste.html")
Simplesmente não deveria funcionar em lugar nenhum. Infelizmente, alguns navegadores permitem fazer esse tipo de coisa com alguns métodos e propriedades, tratando um como se fosse outro. Depois, quando você tentar executar seu script num navegador que segue os padrões e ele não funcionar, saiba que a culpa é sua e não do navegador.
Procure uma boa referência
Os métodos apresentados aqui devem suprir grande parte de suas necessidades, mas não todas. Você vai precisar descobrir algum recurso do javascript ou algum membro novo de um elemento DOM. Se você estudar a documentação de qualquer site cuja url termine com
microsoft.com corre o sério risco de ver seu script funcionando apenas em um navegador. Procure uma boa fonte para estudar, como os tutoriais do <a href="http://www.w3schools.com/">W3Schools de
DHTML,
Javascript,
CSS e
HTML
Variáveis de mesmo nome
Procure utilizar a palavra chave
var antes de definir suas variáveis de escopo local, assim:
CODE
function contador(){
<strong>var contador=0</strong>
. . .
}
Isso vai garantir que sua variável
contador não conflite com outra variável de mesmo nome em outra função.
Boas práticas de codificação
Mantenha seu código limpo, indentado e comentado. Coloque nomes nas variáveis que representem de fato sua função. Cuide do encapsulamento do código e tente escrever funções reaproveitáveis. Tenha uma biblioteca organizada de scripts úteis. Isso vai te fazer ganhar mais tempo do que imagina.
Conheça Javascript
A linguagem é sua ferramenta. Saiba manuseá-la bem. Veja este código:
CODE
function inverte(){
objSelect=document.form1.select1
for(var i=0;i<objSelect.options.length;i++){
if(objSelect.options[i].selected==true){
objSelect.options[i].selected=false
}else{
objSelect.options[i].selected=true
}
}
objSelect=document.form1.select2
for(var i=0;i<objSelect.options.length;i++){
if(objSelect.options[i].selected==true){
objSelect.options[i].selected=false
}else{
objSelect.options[i].selected=true
}
}
...
objSelect=document.form1.select20
for(var i=0;i<objSelect.options.length;i++){
if(objSelect.options[i].selected==true){
objSelect.options[i].selected=false
}else{
objSelect.options[i].selected=true
}
}
}
Não há nada de errado com a lógica, mas é extenso, e difícil de manter. Pode ser trocado, com facilidade, por:
CODE
function inverte(){
var f=document.form1
for(var sel=0;sel<20;objSel=eval("f.select"+(++sel))
for(var i=0;i<objSel.options.length;i++)
objSel.options[i].selected=!objSel.options[i].selected
}
Há muita gente por aí que, por pura falta de intimidade com a linguagem, escreve muito código como o primeiro. Então tome tempo para estudar linguagem, será um tempo bem gasto.
Comentários:
Pinguim disse:
Ajuda bastante ^^
Micox disse:
Muito bom o trabalho do Elcio.
luishenrique disse:
Elomar França disse:
Show de bola mesmo!
Quem quiser ir um pouco mais fundo no html+css+js, tem uns links aqui: [http://codando.wordpress.com/2008/02/16/minicursos-1-html-css-js/]
Ver o restante dos comentários no fórum (e aproveitar pra comentar também !).