Vamos começar revisitando um diagrama de algumas aulas atrás:

Lembre-se que na maioria das interações online, temos um cliente/usuário que envia uma Requisição HTTP para um servidor, que envia de volta uma Resposta HTTP. Todo o código Python que escrevemos até agora usando Django foi executado no servidor. JavaScript nos permitirá executar código no lado do cliente, significando que nenhuma interação com o servidor é necessária enquanto ele está rodando, permitindo que nossos sites se tornem muito mais interativos.
Para adicionar JavaScript à nossa página, podemos adicionar uma par de tags <script> em algum lugar do nosso HTML. Usamos tags <script> para sinalizar ao navegador que qualquer coisa que escrevemos entre elas é código JavaScript que queremos executar quando um usuário visita nosso site. Nosso primeiro programa pode se parecer com isso:
alert('Olá, kaiqui!');
A função alert em JavaScript exibe uma mensagem ao usuário que pode então ser dispensada. Para mostrar onde isso se encaixaria em um documento HTML real, aqui está um exemplo de uma página simples com algum JavaScript:
<!DOCTYPE html>
<html lang="pt">
<head>
<title>Olá</title>
<script>
alert('Olá, kaiqui!');
</script>
</head>
<body>
<h1>Olá!</h1>
</body>
</html>

Uma característica do JavaScript que o torna útil para programação web é seu suporte a Programação Orientada a Eventos.
Programação Orientada a Eventos é um paradigma que se concentra na detecção de eventos e ações que devem ser tomadas quando um evento é detectado.
Um evento pode ser quase qualquer coisa incluindo um botão sendo clicado, o cursor sendo movido, uma resposta sendo digitada ou uma página sendo carregada. Quase tudo que um usuário faz para interagir com uma página web pode ser considerado um evento. Em JavaScript, usamos Ouvintes de Evento que esperam por certos eventos ocorrerem e então executam algum código.
Vamos começar transformando nosso JavaScript de antes em uma função chamada ola:
function ola() {
alert('Olá, mundo!')
}
Agora, vamos fazer com que esta função seja executada quando um botão for clicado. Para isso, criaremos um botão HTML em nossa página com um atributo onclick, que dá ao navegador instruções sobre o que deve acontecer quando o botão é clicado:
<button onclick="ola()">Clique Aqui</button>
Estas mudanças nos permitem esperar para executar partes do nosso código JavaScript até que certo evento ocorra.
JavaScript é uma linguagem de programação como Python, C ou qualquer outra linguagem com que você já trabalhou, significando que tem muitas das mesmas características incluindo variáveis. Há três palavras-chave que podemos usar para atribuir valores em JavaScript:
var: usado para definir uma variável globalmentevar idade = 20;
let: usado para definir uma variável com escopo limitado ao bloco atual como uma função ou looplet contador = 1;
const: usado para definir um valor que não mudaráconst PI = 3.14;
Para um exemplo de como podemos usar uma variável, vamos ver uma página que mantém um contador:
<!DOCTYPE html>
<html lang="pt">
<head>
<title>Contador</title>
<script>
let contador = 0;
function contar() {
contador++;
alert(contador);
}
</script>
</head>
<body>
<h1>Olá!</h1>
<button onclick="contar()">Contar</button>
</body>
</html>

Além de nos permitir mostrar mensagens através de alertas, JavaScript também nos permite mudar elementos na página. Para fazer isso, devemos primeiro introduzir uma função chamada document.querySelector. Esta função procura e retorna elementos do DOM. Por exemplo, usaríamos:
let cabecalho = document.querySelector('h1');
para extrair um cabeçalho. Então, para manipular o elemento que encontramos, podemos mudar sua propriedade innerHTML:
cabecalho.innerHTML = `Adeus!`;
Assim como em Python, também podemos aproveitar condições em JavaScript. Por exemplo, digamos que ao invés de sempre mudar nosso cabeçalho para Adeus!, queremos alternar entre Olá! e Adeus!. Nossa página poderia então se parecer com a abaixo. Note que em JavaScript, usamos === como uma comparação mais forte entre dois itens que também verifica que os objetos são do mesmo tipo. Geralmente queremos usar === sempre que possível.
<!DOCTYPE html>
<html lang="pt">
<head>
<title>Contador</title>
<script>
function ola() {
const cabecalho = document.querySelector('h1');
if (cabecalho.innerHTML === 'Olá!') {
cabecalho.innerHTML = 'Adeus!';
}
else {
cabecalho.innerHTML = 'Olá!';
}
}
</script>
</head>
<body>
<h1>Olá!</h1>
<button onclick="ola()">Clique Aqui</button>
</body>
</html>

Vamos usar essa ideia de manipulação da DOM para melhorar nossa página de contador:
<!DOCTYPE html>
<html lang="pt">
<head>
<title>Contador</title>
<script>
let contador = 0;
function contar() {
contador++;
document.querySelector('h1').innerHTML = contador;
}
</script>
</head>
<body>
<h1>0</h1>
<button onclick="contar()">Contar</button>
</body>
</html>

Podemos tornar esta página ainda mais interessante exibindo um alerta toda vez que o contador chegar a um múltiplo de dez. Neste alerta, vamos formatar uma string para personalizar a mensagem, o que em JavaScript podemos fazer usando template literals. Template literals requerem que haja crases (`) em torno de toda a expressão e um $ e chaves em torno de qualquer substituição. Por exemplo, vamos mudar nossa função contar:
function contar() {
contador++;
document.querySelector('h1').innerHTML = contador;
if (contador % 10 === 0) {
alert(`Contagem está agora em ${contador}`)
}
}

Agora, vamos ver algumas maneiras de melhorar o design desta página. Primeiro, assim como tentamos evitar estilização inline com CSS, queremos evitar JavaScript inline sempre que possível. Podemos fazer isso em nosso exemplo de contador adicionando uma linha de script que muda o atributo onclick de um botão na página, e removendo o atributo onclick de dentro da tag button.
document.querySelector('button').onclick = contar;
Uma coisa a notar sobre o que acabamos de fazer é que não estamos chamando a função contar adicionando parênteses depois, mas apenas nomeando a função. Isso especifica que só queremos chamar esta função quando o botão for clicado. Isso funciona porque, como Python, JavaScript suporta programação funcional, então funções podem ser tratadas como valores em si mesmas.
Esta mudança sozinha não é suficiente, como podemos ver ao inspecionar a página e olhar o console do navegador:

Este erro apareceu porque quando JavaScript procurou por um elemento usando document.querySelector('button'), não encontrou nada. Isso porque leva um pequeno tempo para a página carregar, e nosso código JavaScript rodou antes do botão ter sido renderizado. Para contornar isso, podemos especificar que o código só será executado depois que a página tiver carregado usando a função addEventListener. Esta função recebe dois argumentos:
'click')ola de antes)Podemos usar a função para só executar o código uma vez que todo o conteúdo tiver carregado:
document.addEventListener('DOMContentLoaded', function() {
// Algum código aqui
});
No exemplo acima, usamos uma função anônima, que é uma função que nunca recebe um nome. Juntando tudo isso, nosso JavaScript agora fica assim:
let contador = 0;
function contar() {
contador++;
document.querySelector('h1').innerHTML = contador;
if (contador % 10 === 0) {
alert(`Contagem está agora em ${contador}`)
}
}
document.addEventListener('DOMContentLoaded', function() {
document.querySelector('button').onclick = contar;
});
Outra maneira de melhorar nosso design é movendo nosso JavaScript para um arquivo separado. A maneira como fazemos isso é muito similar a como colocamos nosso CSS em um arquivo separado para estilização:
.js, talvez index.js.src à tag <script> que aponta para este novo arquivo.Para nossa página de contador, poderíamos ter um arquivo chamado contador.html que se parece com isso:
<!DOCTYPE html>
<html lang="pt">
<head>
<title>Contador</title>
<script src="/static/contador.js"></script>
</head>
<body>
<h1>0</h1>
<button>Contar</button>
</body>
</html>
E um arquivo chamado contador.js que se parece com isso:
let contador = 0;
function contar() {
contador++;
document.querySelector('h1').innerHTML = contador;
if (contador % 10 === 0) {
alert(`Contagem está agora em ${contador}`)
}
}
document.addEventListener('DOMContentLoaded', function() {
document.querySelector('button').onclick = contar;
});
Ter JavaScript em um arquivo separado é útil por várias razões:
Vamos começar outro exemplo de uma página que pode ser um pouco mais interativa. Abaixo, criaremos uma página onde um usuário pode digitar seu nome para receber uma saudação personalizada.
<!DOCTYPE html>
<html lang="pt">
<head>
<title>Olá</title>
<script>
document.addEventListener('DOMContentLoaded', function() {
document.querySelector('form').onsubmit = function() {
const nome = document.querySelector('#nome').value;
alert(`Olá, ${nome}`);
};
});
</script>
</head>
<body>
<form>
<input autofocus id="nome" placeholder="Nome" type="text">
<input type="submit">
</form>
</body>
</html>

Algumas notas sobre a página acima:
autofocus no input nome para indicar que o cursor deve ser posicionado dentro desse input assim que a página carregar.#nome dentro de document.querySelector para encontrar um elemento com um id de nome. Podemos usar todos os mesmos seletores nesta função que poderíamos em CSS.value de um campo de input para encontrar o que está atualmente digitado.Podemos fazer mais do que apenas adicionar HTML à nossa página usando JavaScript, também podemos mudar a estilização de uma página! Na página abaixo, usamos botões para mudar a cor do nosso cabeçalho.
<!DOCTYPE html>
<html lang="pt">
<head>
<title>Cores</title>
<script>
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('button').forEach(function(botao) {
botao.onclick = function() {
document.querySelector("#ola").style.color = botao.dataset.cor;
}
});
});
</script>
</head>
<body>
<h1 id="ola">Olá</h1>
<button data-cor="red">Vermelho</button>
<button data-cor="blue">Azul</button>
<button data-cor="green">Verde</button>
</body>
</html>

Algumas notas sobre a página acima:
style.ALGO.data-ALGO para atribuir dados a um elemento HTML. Podemos depois acessar esses dados em JavaScript usando a propriedade dataset do elemento.querySelectorAll para obter uma Node List (similar a uma lista Python ou um array JavaScript) com todos os elementos que correspondem à query.O console é uma ferramenta útil para testar pequenos pedaços de código e depurar. Você pode escrever e executar código JavaScript no console, que pode ser encontrado inspecionando elemento no seu navegador e então clicando em console. (O processo exato pode variar de navegador para navegador.) Uma ferramenta útil para depuração é imprimir no console, o que você pode fazer usando a função console.log. Por exemplo, na página cores.html acima, posso adicionar a seguinte linha:
console.log(document.querySelectorAll('button'));
O que nos dá isso no console:

Além da notação tradicional de função que já vimos, JavaScript agora nos dá a habilidade de usar Arrow Functions onde temos uma entrada (ou parênteses quando não há entrada) seguido por => seguido por algum código a ser executado. Por exemplo, podemos alterar nosso script acima para usar uma arrow function anônima:
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('button').forEach(botao => {
botao.onclick = () => {
document.querySelector("#ola").style.color = botao.dataset.cor;
}
});
});
Também podemos ter funções nomeadas que usam arrows, como nesta reescrita da função contar:
contar = () => {
contador++;
document.querySelector('h1').innerHTML = contador;
if (contador % 10 === 0) {
alert(`Contagem está agora em ${contador}`)
}
}
Para ter uma ideia sobre outros eventos que podemos usar, vejamos como implementar nosso seletor de cores usando um menu dropdown ao invés de três botões separados. Podemos detectar mudanças em um elemento select usando o atributo onchange. Em JavaScript, this é uma palavra-chave que muda com base no contexto em que é usada. No caso de um manipulador de eventos, this refere-se ao objeto que acionou o evento.
<!DOCTYPE html>
<html lang="pt">
<head>
<title>Cores</title>
<script>
document.addEventListener('DOMContentLoaded', function() {
document.querySelector('select').onchange = function() {
document.querySelector('#ola').style.color = this.value;
}
});
</script>
</head>
<body>
<h1 id="ola">Olá</h1>
<select>
<option value="black">Preto</option>
<option value="red">Vermelho</option>
<option value="blue">Azul</option>
<option value="green">Verde</option>
</select>
</body>
</html>

Há muitos outros eventos que podemos detectar em JavaScript incluindo os comuns abaixo:
onclickonmouseoveronkeydownonkeyuponloadonblurPara juntar algumas das coisas que aprendemos nesta aula, vamos trabalhar em fazer uma lista de tarefas inteiramente em JavaScript. Começaremos escrevendo o layout HTML da página. Note abaixo como deixamos espaço para uma lista não ordenada, mas ainda não adicionamos nada a ela. Também note que adicionamos um link para tarefas.js onde escreveremos nosso JavaScript.
<!DOCTYPE html>
<html lang="pt">
<head>
<title>Tarefas</title>
<script src="/static/tarefas.js"></script>
</head>
<body>
<h1>Tarefas</h1>
<ul id="tarefas"></ul>
<form>
<input id="tarefa" placeholder = "Nova Tarefa" type="text">
<input id="submit" type="submit">
</form>
</body>
</html>
Agora, aqui está nosso código que podemos manter em tarefas.js. Algumas notas sobre o que você verá abaixo:
submit e novaTarefa.disabled para false/true..length para encontrar o comprimento de objetos como strings e arrays.return false. Isso previne o envio padrão do formulário que envolve ou recarregar a página atual ou redirecionar para uma nova.append.// Esperar a página carregar
document.addEventListener('DOMContentLoaded', function() {
// Selecionar o botão de submit e input para usar depois
const submit = document.querySelector('#submit');
const novaTarefa = document.querySelector('#tarefa');
// Desabilitar botão de submit por padrão:
submit.disabled = true;
// Ouvir por input sendo digitado no campo
novaTarefa.onkeyup = () => {
if (novaTarefa.value.length > 0) {
submit.disabled = false;
}
else {
submit.disabled = true;
}
}
// Ouvir por envio de formulário
document.querySelector('form').onsubmit = () => {
// Encontrar a tarefa que o usuário acabou de enviar
const tarefa = novaTarefa.value;
// Criar um item de lista para a nova tarefa e adicionar a tarefa a ele
const li = document.createElement('li');
li.innerHTML = tarefa;
// Adicionar novo elemento à nossa lista não ordenada:
document.querySelector('#tarefas').append(li);
// Limpar campo de input:
novaTarefa.value = '';
// Desabilitar o botão de submit novamente:
submit.disabled = true;
// Parar o formulário de enviar
return false;
}
});

Além de especificar que funções rodam quando um evento é acionado, também podemos configurar funções para rodar após um certo tempo. Por exemplo, vamos voltar ao script da nossa página de contador, e adicionar um intervalo para que mesmo se o usuário não clicar em nada, o contador incremente a cada segundo. Para fazer isso, usamos a função setInterval, que recebe como argumento uma função a ser executada, e um tempo (em milissegundos) entre execuções da função.
let contador = 0;
function contar() {
contador++;
document.querySelector('h1').innerHTML = contador;
}
document.addEventListener('DOMContentLoaded', function() {
document.querySelector('button').onclick = contar;
setInterval(contar, 1000);
});

Uma coisa a notar sobre todos os nossos sites até agora é que toda vez que recarregamos a página, toda nossa informação é perdida. A cor do cabeçalho volta para preto, o contador volta para 0, e todas as tarefas são apagadas. Às vezes isso é o que pretendemos, mas outras vezes vamos querer poder armazenar informação que podemos usar quando um usuário retornar ao site.
Uma maneira que podemos fazer isso é usando Local Storage, ou armazenando informação no navegador do usuário que podemos acessar depois. Esta informação é armazenada como um conjunto de pares chave-valor, quase como um dicionário Python. Para usar local storage, empregaremos duas funções chave:
localStorage.getItem(chave): Esta função procura por uma entrada no local storage com uma dada chave, e retorna o valor associado a essa chave.localStorage.setItem(chave, valor): Esta função configura uma entrada no local storage, associando a chave com um novo valor.Vamos ver como podemos usar essas novas funções para atualizar nosso contador! No código abaixo,
// Verificar se já existe um valor no local storage
if (!localStorage.getItem('contador')) {
// Se não, configurar o contador para 0 no local storage
localStorage.setItem('contador', 0);
}
function contar() {
// Recuperar valor do contador do local storage
let contador = localStorage.getItem('contador');
// atualizar contador
contador++;
document.querySelector('h1').innerHTML = contador;
// Armazenar contador no local storage
localStorage.setItem('contador', contador);
}
document.addEventListener('DOMContentLoaded', function() {
// Configurar cabeçalho para o valor atual dentro do local storage
document.querySelector('h1').innerHTML = localStorage.getItem('contador');
document.querySelector('button').onclick = contar;
});

Isso é tudo para esta aula! Na próxima, trabalharemos em usar JavaScript para criar interfaces de usuário ainda mais engajadoras!