|
|
<!--
|
|
|
CO_OP_TRANSLATOR_METADATA:
|
|
|
{
|
|
|
"original_hash": "973e48ad87d67bf5bb819746c9f8e302",
|
|
|
"translation_date": "2025-11-04T00:06:49+00:00",
|
|
|
"source_file": "3-terrarium/3-intro-to-DOM-and-closures/README.md",
|
|
|
"language_code": "br"
|
|
|
}
|
|
|
-->
|
|
|
# Projeto Terrário Parte 3: Manipulação do DOM e Closures em JavaScript
|
|
|
|
|
|
```mermaid
|
|
|
journey
|
|
|
title Your JavaScript DOM Journey
|
|
|
section Foundation
|
|
|
Understand DOM: 3: Student
|
|
|
Learn closures: 4: Student
|
|
|
Connect elements: 4: Student
|
|
|
section Interaction
|
|
|
Setup drag events: 4: Student
|
|
|
Track coordinates: 5: Student
|
|
|
Handle movement: 5: Student
|
|
|
section Polish
|
|
|
Add cleanup: 4: Student
|
|
|
Test functionality: 5: Student
|
|
|
Complete terrarium: 5: Student
|
|
|
```
|
|
|
|
|
|

|
|
|
> Sketchnote por [Tomomi Imura](https://twitter.com/girlie_mac)
|
|
|
|
|
|
Bem-vindo a um dos aspectos mais envolventes do desenvolvimento web - tornar as coisas interativas! O Modelo de Objeto de Documento (DOM) é como uma ponte entre seu HTML e JavaScript, e hoje vamos usá-lo para dar vida ao seu terrário. Quando Tim Berners-Lee criou o primeiro navegador web, ele imaginou uma web onde os documentos poderiam ser dinâmicos e interativos - o DOM torna essa visão possível.
|
|
|
|
|
|
Também exploraremos closures em JavaScript, que podem parecer intimidantes à primeira vista. Pense nos closures como "bolsos de memória" onde suas funções podem lembrar informações importantes. É como se cada planta no seu terrário tivesse seu próprio registro de dados para acompanhar sua posição. Ao final desta lição, você entenderá como eles são naturais e úteis.
|
|
|
|
|
|
Aqui está o que estamos construindo: um terrário onde os usuários podem arrastar e soltar plantas onde quiserem. Você aprenderá as técnicas de manipulação do DOM que alimentam tudo, desde uploads de arquivos com arrastar e soltar até jogos interativos. Vamos dar vida ao seu terrário.
|
|
|
|
|
|
```mermaid
|
|
|
mindmap
|
|
|
root((DOM & JavaScript))
|
|
|
DOM Tree
|
|
|
Element Selection
|
|
|
Property Access
|
|
|
Event Handling
|
|
|
Dynamic Updates
|
|
|
Events
|
|
|
Pointer Events
|
|
|
Mouse Events
|
|
|
Touch Events
|
|
|
Event Listeners
|
|
|
Closures
|
|
|
Private Variables
|
|
|
Function Scope
|
|
|
Memory Persistence
|
|
|
State Management
|
|
|
Drag & Drop
|
|
|
Position Tracking
|
|
|
Coordinate Math
|
|
|
Event Lifecycle
|
|
|
User Interaction
|
|
|
Modern Patterns
|
|
|
Event Delegation
|
|
|
Performance
|
|
|
Cross-Device
|
|
|
Accessibility
|
|
|
```
|
|
|
|
|
|
## Quiz Pré-Aula
|
|
|
|
|
|
[Quiz pré-aula](https://ff-quizzes.netlify.app/web/quiz/19)
|
|
|
|
|
|
## Entendendo o DOM: Sua Porta de Entrada para Páginas Web Interativas
|
|
|
|
|
|
O Modelo de Objeto de Documento (DOM) é como o JavaScript se comunica com os elementos HTML. Quando seu navegador carrega uma página HTML, ele cria uma representação estruturada dessa página na memória - isso é o DOM. Pense nele como uma árvore genealógica onde cada elemento HTML é um membro da família que o JavaScript pode acessar, modificar ou reorganizar.
|
|
|
|
|
|
A manipulação do DOM transforma páginas estáticas em sites interativos. Toda vez que você vê um botão mudar de cor ao passar o mouse, conteúdo sendo atualizado sem recarregar a página ou elementos que você pode arrastar, isso é manipulação do DOM em ação.
|
|
|
|
|
|
```mermaid
|
|
|
flowchart TD
|
|
|
A["Document"] --> B["HTML"]
|
|
|
B --> C["Head"]
|
|
|
B --> D["Body"]
|
|
|
C --> E["Title"]
|
|
|
C --> F["Meta Tags"]
|
|
|
D --> G["H1: My Terrarium"]
|
|
|
D --> H["Div: Page Container"]
|
|
|
H --> I["Div: Left Container"]
|
|
|
H --> J["Div: Right Container"]
|
|
|
H --> K["Div: Terrarium"]
|
|
|
I --> L["Plant Elements 1-7"]
|
|
|
J --> M["Plant Elements 8-14"]
|
|
|
|
|
|
L --> N["img#plant1"]
|
|
|
L --> O["img#plant2"]
|
|
|
M --> P["img#plant8"]
|
|
|
M --> Q["img#plant9"]
|
|
|
|
|
|
style A fill:#e1f5fe
|
|
|
style B fill:#f3e5f5
|
|
|
style D fill:#e8f5e8
|
|
|
style H fill:#fff3e0
|
|
|
style N fill:#ffebee
|
|
|
style O fill:#ffebee
|
|
|
style P fill:#ffebee
|
|
|
style Q fill:#ffebee
|
|
|
```
|
|
|
|
|
|

|
|
|
|
|
|
> Uma representação do DOM e da marcação HTML que o referencia. De [Olfa Nasraoui](https://www.researchgate.net/publication/221417012_Profile-Based_Focused_Crawler_for_Social_Media-Sharing_Websites)
|
|
|
|
|
|
**Aqui está o que torna o DOM poderoso:**
|
|
|
- **Fornece** uma maneira estruturada de acessar qualquer elemento na sua página
|
|
|
- **Permite** atualizações dinâmicas de conteúdo sem recarregar a página
|
|
|
- **Responde** em tempo real às interações do usuário, como cliques e arrastos
|
|
|
- **Cria** a base para aplicativos web modernos e interativos
|
|
|
|
|
|
## Closures em JavaScript: Criando Código Organizado e Poderoso
|
|
|
|
|
|
Um [closure em JavaScript](https://developer.mozilla.org/docs/Web/JavaScript/Closures) é como dar a uma função seu próprio espaço privado com memória persistente. Considere como os tentilhões de Darwin nas Ilhas Galápagos desenvolveram bicos especializados com base em seus ambientes específicos - closures funcionam de forma semelhante, criando funções especializadas que "lembram" seu contexto específico mesmo após a função pai ter terminado.
|
|
|
|
|
|
No nosso terrário, closures ajudam cada planta a lembrar sua própria posição de forma independente. Esse padrão aparece em todo o desenvolvimento profissional de JavaScript, tornando-o um conceito valioso para entender.
|
|
|
|
|
|
```mermaid
|
|
|
flowchart LR
|
|
|
A["dragElement(plant1)"] --> B["Creates Closure"]
|
|
|
A2["dragElement(plant2)"] --> B2["Creates Closure"]
|
|
|
|
|
|
B --> C["Private Variables"]
|
|
|
B2 --> C2["Private Variables"]
|
|
|
|
|
|
C --> D["pos1, pos2, pos3, pos4"]
|
|
|
C --> E["pointerDrag function"]
|
|
|
C --> F["elementDrag function"]
|
|
|
C --> G["stopElementDrag function"]
|
|
|
|
|
|
C2 --> D2["pos1, pos2, pos3, pos4"]
|
|
|
C2 --> E2["pointerDrag function"]
|
|
|
C2 --> F2["elementDrag function"]
|
|
|
C2 --> G2["stopElementDrag function"]
|
|
|
|
|
|
H["Plant 1 remembers its position"] --> B
|
|
|
H2["Plant 2 remembers its position"] --> B2
|
|
|
|
|
|
style B fill:#e8f5e8
|
|
|
style B2 fill:#e8f5e8
|
|
|
style C fill:#fff3e0
|
|
|
style C2 fill:#fff3e0
|
|
|
```
|
|
|
|
|
|
> 💡 **Entendendo Closures**: Closures são um tópico significativo em JavaScript, e muitos desenvolvedores os utilizam por anos antes de compreender totalmente todos os aspectos teóricos. Hoje, estamos focando na aplicação prática - você verá closures surgirem naturalmente enquanto construímos nossos recursos interativos. A compreensão se desenvolverá à medida que você perceber como eles resolvem problemas reais.
|
|
|
|
|
|

|
|
|
|
|
|
> Uma representação do DOM e da marcação HTML que o referencia. De [Olfa Nasraoui](https://www.researchgate.net/publication/221417012_Profile-Based_Focused_Crawler_for_Social_Media-Sharing_Websites)
|
|
|
|
|
|
Nesta lição, completaremos nosso projeto de terrário interativo criando o JavaScript que permitirá ao usuário manipular as plantas na página.
|
|
|
|
|
|
## Antes de Começar: Preparando-se para o Sucesso
|
|
|
|
|
|
Você precisará dos arquivos HTML e CSS das lições anteriores do terrário - estamos prestes a tornar esse design estático interativo. Se você está começando agora, completar essas lições primeiro fornecerá um contexto importante.
|
|
|
|
|
|
Aqui está o que vamos construir:
|
|
|
- **Arrastar e soltar suave** para todas as plantas do terrário
|
|
|
- **Rastreamento de coordenadas** para que as plantas lembrem suas posições
|
|
|
- **Uma interface interativa completa** usando JavaScript puro
|
|
|
- **Código limpo e organizado** utilizando padrões de closure
|
|
|
|
|
|
## Configurando Seu Arquivo JavaScript
|
|
|
|
|
|
Vamos criar o arquivo JavaScript que tornará seu terrário interativo.
|
|
|
|
|
|
**Passo 1: Crie seu arquivo de script**
|
|
|
|
|
|
Na pasta do seu terrário, crie um novo arquivo chamado `script.js`.
|
|
|
|
|
|
**Passo 2: Vincule o JavaScript ao seu HTML**
|
|
|
|
|
|
Adicione esta tag de script à seção `<head>` do seu arquivo `index.html`:
|
|
|
|
|
|
```html
|
|
|
<script src="./script.js" defer></script>
|
|
|
```
|
|
|
|
|
|
**Por que o atributo `defer` é importante:**
|
|
|
- **Garante** que seu JavaScript espere até que todo o HTML seja carregado
|
|
|
- **Previne** erros onde o JavaScript procura por elementos que ainda não estão prontos
|
|
|
- **Assegura** que todos os elementos das plantas estejam disponíveis para interação
|
|
|
- **Oferece** melhor desempenho do que colocar scripts no final da página
|
|
|
|
|
|
> ⚠️ **Nota Importante**: O atributo `defer` previne problemas comuns de tempo. Sem ele, o JavaScript pode tentar acessar elementos HTML antes de serem carregados, causando erros.
|
|
|
|
|
|
---
|
|
|
|
|
|
## Conectando JavaScript aos Elementos HTML
|
|
|
|
|
|
Antes de podermos tornar os elementos arrastáveis, o JavaScript precisa localizá-los no DOM. Pense nisso como um sistema de catalogação de biblioteca - uma vez que você tem o número do catálogo, pode encontrar exatamente o livro que precisa e acessar todo o seu conteúdo.
|
|
|
|
|
|
Usaremos o método `document.getElementById()` para fazer essas conexões. É como ter um sistema de arquivamento preciso - você fornece um ID e ele localiza exatamente o elemento que você precisa no seu HTML.
|
|
|
|
|
|
### Habilitando Funcionalidade de Arrastar para Todas as Plantas
|
|
|
|
|
|
Adicione este código ao seu arquivo `script.js`:
|
|
|
|
|
|
```javascript
|
|
|
// Enable drag functionality for all 14 plants
|
|
|
dragElement(document.getElementById('plant1'));
|
|
|
dragElement(document.getElementById('plant2'));
|
|
|
dragElement(document.getElementById('plant3'));
|
|
|
dragElement(document.getElementById('plant4'));
|
|
|
dragElement(document.getElementById('plant5'));
|
|
|
dragElement(document.getElementById('plant6'));
|
|
|
dragElement(document.getElementById('plant7'));
|
|
|
dragElement(document.getElementById('plant8'));
|
|
|
dragElement(document.getElementById('plant9'));
|
|
|
dragElement(document.getElementById('plant10'));
|
|
|
dragElement(document.getElementById('plant11'));
|
|
|
dragElement(document.getElementById('plant12'));
|
|
|
dragElement(document.getElementById('plant13'));
|
|
|
dragElement(document.getElementById('plant14'));
|
|
|
```
|
|
|
|
|
|
**Aqui está o que este código realiza:**
|
|
|
- **Localiza** cada elemento de planta no DOM usando seu ID único
|
|
|
- **Recupera** uma referência JavaScript para cada elemento HTML
|
|
|
- **Passa** cada elemento para uma função `dragElement` (que criaremos a seguir)
|
|
|
- **Prepara** cada planta para interação de arrastar e soltar
|
|
|
- **Conecta** sua estrutura HTML à funcionalidade JavaScript
|
|
|
|
|
|
> 🎯 **Por que Usar IDs em vez de Classes?** IDs fornecem identificadores únicos para elementos específicos, enquanto classes CSS são projetadas para estilizar grupos de elementos. Quando o JavaScript precisa manipular elementos individuais, IDs oferecem a precisão e o desempenho necessários.
|
|
|
|
|
|
> 💡 **Dica Pro**: Note como estamos chamando `dragElement()` para cada planta individualmente. Essa abordagem garante que cada planta tenha seu próprio comportamento de arrastar independente, essencial para uma interação suave do usuário.
|
|
|
|
|
|
### 🔄 **Verificação Pedagógica**
|
|
|
**Entendimento da Conexão DOM**: Antes de avançar para a funcionalidade de arrastar, verifique se você consegue:
|
|
|
- ✅ Explicar como `document.getElementById()` localiza elementos HTML
|
|
|
- ✅ Entender por que usamos IDs únicos para cada planta
|
|
|
- ✅ Descrever o propósito do atributo `defer` em tags de script
|
|
|
- ✅ Reconhecer como JavaScript e HTML se conectam através do DOM
|
|
|
|
|
|
**Teste Rápido**: O que aconteceria se dois elementos tivessem o mesmo ID? Por que `getElementById()` retorna apenas um elemento?
|
|
|
*Resposta: IDs devem ser únicos; se duplicados, apenas o primeiro elemento é retornado*
|
|
|
|
|
|
---
|
|
|
|
|
|
## Construindo o Closure da Função Drag Element
|
|
|
|
|
|
Agora vamos criar o coração da nossa funcionalidade de arrastar: um closure que gerencia o comportamento de arrastar para cada planta. Este closure conterá várias funções internas que trabalham juntas para rastrear movimentos do mouse e atualizar posições dos elementos.
|
|
|
|
|
|
Closures são perfeitos para essa tarefa porque permitem criar variáveis "privadas" que persistem entre chamadas de função, dando a cada planta seu próprio sistema independente de rastreamento de coordenadas.
|
|
|
|
|
|
### Entendendo Closures com um Exemplo Simples
|
|
|
|
|
|
Deixe-me demonstrar closures com um exemplo simples que ilustra o conceito:
|
|
|
|
|
|
```javascript
|
|
|
function createCounter() {
|
|
|
let count = 0; // This is like a private variable
|
|
|
|
|
|
function increment() {
|
|
|
count++; // The inner function remembers the outer variable
|
|
|
return count;
|
|
|
}
|
|
|
|
|
|
return increment; // We're giving back the inner function
|
|
|
}
|
|
|
|
|
|
const myCounter = createCounter();
|
|
|
console.log(myCounter()); // 1
|
|
|
console.log(myCounter()); // 2
|
|
|
```
|
|
|
|
|
|
**Aqui está o que está acontecendo neste padrão de closure:**
|
|
|
- **Cria** uma variável privada `count` que existe apenas dentro deste closure
|
|
|
- **A função interna** pode acessar e modificar essa variável externa (o mecanismo de closure)
|
|
|
- **Quando retornamos** a função interna, ela mantém sua conexão com esses dados privados
|
|
|
- **Mesmo depois** que `createCounter()` termina a execução, `count` persiste e lembra seu valor
|
|
|
|
|
|
### Por que Closures São Perfeitos para a Funcionalidade de Arrastar
|
|
|
|
|
|
Para nosso terrário, cada planta precisa lembrar suas coordenadas atuais. Closures fornecem a solução perfeita:
|
|
|
|
|
|
**Benefícios principais para nosso projeto:**
|
|
|
- **Mantém** variáveis privadas de posição para cada planta de forma independente
|
|
|
- **Preserva** dados de coordenadas entre eventos de arrastar
|
|
|
- **Previne** conflitos de variáveis entre diferentes elementos arrastáveis
|
|
|
- **Cria** uma estrutura de código limpa e organizada
|
|
|
|
|
|
> 🎯 **Objetivo de Aprendizado**: Você não precisa dominar todos os aspectos de closures agora. Foque em ver como eles ajudam a organizar o código e manter o estado para nossa funcionalidade de arrastar.
|
|
|
|
|
|
```mermaid
|
|
|
stateDiagram-v2
|
|
|
[*] --> Ready: Page loads
|
|
|
Ready --> DragStart: User presses down (pointerdown)
|
|
|
DragStart --> Dragging: Mouse/finger moves (pointermove)
|
|
|
Dragging --> Dragging: Continue moving
|
|
|
Dragging --> DragEnd: User releases (pointerup)
|
|
|
DragEnd --> Ready: Reset for next drag
|
|
|
|
|
|
state DragStart {
|
|
|
[*] --> CapturePosition
|
|
|
CapturePosition --> SetupListeners
|
|
|
SetupListeners --> [*]
|
|
|
}
|
|
|
|
|
|
state Dragging {
|
|
|
[*] --> CalculateMovement
|
|
|
CalculateMovement --> UpdatePosition
|
|
|
UpdatePosition --> [*]
|
|
|
}
|
|
|
|
|
|
state DragEnd {
|
|
|
[*] --> RemoveListeners
|
|
|
RemoveListeners --> CleanupState
|
|
|
CleanupState --> [*]
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### Criando a Função dragElement
|
|
|
|
|
|
Agora vamos construir a função principal que lidará com toda a lógica de arrastar. Adicione esta função abaixo das declarações dos elementos das plantas:
|
|
|
|
|
|
```javascript
|
|
|
function dragElement(terrariumElement) {
|
|
|
// Initialize position tracking variables
|
|
|
let pos1 = 0, // Previous mouse X position
|
|
|
pos2 = 0, // Previous mouse Y position
|
|
|
pos3 = 0, // Current mouse X position
|
|
|
pos4 = 0; // Current mouse Y position
|
|
|
|
|
|
// Set up the initial drag event listener
|
|
|
terrariumElement.onpointerdown = pointerDrag;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
**Entendendo o sistema de rastreamento de posição:**
|
|
|
- **`pos1` e `pos2`**: Armazenam a diferença entre as posições antigas e novas do mouse
|
|
|
- **`pos3` e `pos4`**: Rastreiam as coordenadas atuais do mouse
|
|
|
- **`terrariumElement`**: O elemento específico da planta que estamos tornando arrastável
|
|
|
- **`onpointerdown`**: O evento que é acionado quando o usuário começa a arrastar
|
|
|
|
|
|
**Aqui está como o padrão de closure funciona:**
|
|
|
- **Cria** variáveis privadas de posição para cada elemento de planta
|
|
|
- **Mantém** essas variáveis ao longo do ciclo de vida do arrastar
|
|
|
- **Garante** que cada planta rastreie suas próprias coordenadas de forma independente
|
|
|
- **Fornece** uma interface limpa através da função `dragElement`
|
|
|
|
|
|
### Por que Usar Eventos de Ponteiro?
|
|
|
|
|
|
Você pode se perguntar por que usamos `onpointerdown` em vez do mais familiar `onclick`. Aqui está o raciocínio:
|
|
|
|
|
|
| Tipo de Evento | Melhor Para | O Problema |
|
|
|
|----------------|-------------|------------|
|
|
|
| `onclick` | Cliques simples em botões | Não consegue lidar com arrastar (apenas cliques e soltar) |
|
|
|
| `onpointerdown` | Mouse e toque | Mais recente, mas bem suportado atualmente |
|
|
|
| `onmousedown` | Apenas mouse de desktop | Exclui usuários móveis |
|
|
|
|
|
|
**Por que eventos de ponteiro são perfeitos para o que estamos construindo:**
|
|
|
- **Funciona bem** seja alguém usando um mouse, dedo ou até mesmo uma caneta
|
|
|
- **Sente-se igual** em um laptop, tablet ou celular
|
|
|
- **Lida** com o movimento real de arrastar (não apenas clicar e soltar)
|
|
|
- **Cria** uma experiência suave que os usuários esperam de aplicativos web modernos
|
|
|
|
|
|
> 💡 **Preparando para o Futuro**: Eventos de ponteiro são a maneira moderna de lidar com interações do usuário. Em vez de escrever código separado para mouse e toque, você obtém ambos de forma integrada. Bem legal, né?
|
|
|
|
|
|
### 🔄 **Verificação Pedagógica**
|
|
|
**Entendimento de Manipulação de Eventos**: Pause para confirmar sua compreensão sobre eventos:
|
|
|
- ✅ Por que usamos eventos de ponteiro em vez de eventos de mouse?
|
|
|
- ✅ Como as variáveis de closure persistem entre chamadas de função?
|
|
|
- ✅ Qual é o papel do `preventDefault()` em um arrastar suave?
|
|
|
- ✅ Por que anexamos ouvintes ao documento em vez de elementos individuais?
|
|
|
|
|
|
**Conexão com o Mundo Real**: Pense sobre interfaces de arrastar e soltar que você usa diariamente:
|
|
|
- **Uploads de arquivos**: Arrastar arquivos para uma janela do navegador
|
|
|
- **Quadros Kanban**: Movendo tarefas entre colunas
|
|
|
- **Galerias de imagens**: Reorganizando a ordem das fotos
|
|
|
- **Interfaces móveis**: Deslizando e arrastando em telas sensíveis ao toque
|
|
|
|
|
|
---
|
|
|
|
|
|
## A Função pointerDrag: Capturando o Início de um Arrastar
|
|
|
|
|
|
Quando um usuário pressiona uma planta (seja com um clique do mouse ou toque do dedo), a função `pointerDrag` entra em ação. Esta função captura as coordenadas iniciais e configura o sistema de arrastar.
|
|
|
|
|
|
Adicione esta função dentro do seu closure `dragElement`, logo após a linha `terrariumElement.onpointerdown = pointerDrag;`:
|
|
|
|
|
|
```javascript
|
|
|
function pointerDrag(e) {
|
|
|
// Prevent default browser behavior (like text selection)
|
|
|
e.preventDefault();
|
|
|
|
|
|
// Capture the initial mouse/touch position
|
|
|
pos3 = e.clientX; // X coordinate where drag started
|
|
|
pos4 = e.clientY; // Y coordinate where drag started
|
|
|
|
|
|
// Set up event listeners for the dragging process
|
|
|
document.onpointermove = elementDrag;
|
|
|
document.onpointerup = stopElementDrag;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
**Passo a passo, aqui está o que está acontecendo:**
|
|
|
- **Previne** comportamentos padrão do navegador que podem interferir no arrastar
|
|
|
- **Registra** as coordenadas exatas onde o usuário iniciou o gesto de arrastar
|
|
|
- **Estabelece** ouvintes de eventos para o movimento contínuo de arrastar
|
|
|
- **Prepara** o sistema para rastrear o movimento do mouse/dedo em todo o documento
|
|
|
|
|
|
### Entendendo a Prevenção de Eventos
|
|
|
|
|
|
A linha `e.preventDefault()` é crucial para um arrastar suave:
|
|
|
|
|
|
**Sem prevenção, os navegadores podem:**
|
|
|
- **Selecionar** texto ao arrastar pela página
|
|
|
- **Acionar** menus de contexto ao clicar com o botão direito durante o arrastar
|
|
|
- **Interferir** no comportamento personalizado de arrastar
|
|
|
- **Criar** artefatos visuais durante a operação de arrastar
|
|
|
|
|
|
> 🔍 **Experimente**: Após completar esta lição, tente remover `e.preventDefault()` e veja como isso afeta a experiência de arrastar. Você rapidamente entenderá por que essa linha é essencial!
|
|
|
|
|
|
### Sistema de Rastreamento de Coordenadas
|
|
|
|
|
|
As propriedades `e.clientX` e `e.clientY` nos dão coordenadas precisas do mouse/toque:
|
|
|
|
|
|
| Propriedade | O que Mede | Caso de Uso |
|
|
|
|-------------|------------|-------------|
|
|
|
| `clientX` | Posição horizontal relativa à janela de visualização | Rastreamento de movimento esquerda-direita |
|
|
|
| `clientY` | Posição vertical relativa à janela de visualização | Rastreamento de movimento cima-baixo |
|
|
|
**Entendendo essas coordenadas:**
|
|
|
- **Fornece** informações de posicionamento precisas em pixels
|
|
|
- **Atualiza** em tempo real conforme o usuário move o ponteiro
|
|
|
- **Permanece** consistente em diferentes tamanhos de tela e níveis de zoom
|
|
|
- **Permite** interações de arrastar suaves e responsivas
|
|
|
|
|
|
### Configurando Listeners de Eventos no Nível do Documento
|
|
|
|
|
|
Observe como vinculamos os eventos de movimento e parada ao `document` inteiro, e não apenas ao elemento planta:
|
|
|
|
|
|
```javascript
|
|
|
document.onpointermove = elementDrag;
|
|
|
document.onpointerup = stopElementDrag;
|
|
|
```
|
|
|
|
|
|
**Por que vincular ao documento:**
|
|
|
- **Continua** rastreando mesmo quando o mouse sai do elemento planta
|
|
|
- **Previne** interrupções no arrasto caso o usuário mova rapidamente
|
|
|
- **Proporciona** arrasto suave em toda a tela
|
|
|
- **Lida** com casos extremos onde o cursor sai da janela do navegador
|
|
|
|
|
|
> ⚡ **Nota de Desempenho**: Limpamos esses listeners no nível do documento quando o arrasto para para evitar vazamentos de memória e problemas de desempenho.
|
|
|
|
|
|
## Completando o Sistema de Arrasto: Movimento e Limpeza
|
|
|
|
|
|
Agora adicionaremos as duas funções restantes que lidam com o movimento real de arrasto e a limpeza quando o arrasto para. Essas funções trabalham juntas para criar um movimento suave e responsivo da planta no seu terrário.
|
|
|
|
|
|
### A Função elementDrag: Rastreamento de Movimento
|
|
|
|
|
|
Adicione a função `elementDrag` logo após a chave de fechamento de `pointerDrag`:
|
|
|
|
|
|
```javascript
|
|
|
function elementDrag(e) {
|
|
|
// Calculate the distance moved since the last event
|
|
|
pos1 = pos3 - e.clientX; // Horizontal distance moved
|
|
|
pos2 = pos4 - e.clientY; // Vertical distance moved
|
|
|
|
|
|
// Update the current position tracking
|
|
|
pos3 = e.clientX; // New current X position
|
|
|
pos4 = e.clientY; // New current Y position
|
|
|
|
|
|
// Apply the movement to the element's position
|
|
|
terrariumElement.style.top = (terrariumElement.offsetTop - pos2) + 'px';
|
|
|
terrariumElement.style.left = (terrariumElement.offsetLeft - pos1) + 'px';
|
|
|
}
|
|
|
```
|
|
|
|
|
|
**Entendendo a matemática das coordenadas:**
|
|
|
- **`pos1` e `pos2`**: Calculam o quanto o mouse se moveu desde a última atualização
|
|
|
- **`pos3` e `pos4`**: Armazenam a posição atual do mouse para o próximo cálculo
|
|
|
- **`offsetTop` e `offsetLeft`**: Obtêm a posição atual do elemento na página
|
|
|
- **Lógica de subtração**: Move o elemento na mesma quantidade que o mouse se moveu
|
|
|
|
|
|
```mermaid
|
|
|
sequenceDiagram
|
|
|
participant User
|
|
|
participant Mouse
|
|
|
participant JavaScript
|
|
|
participant Plant
|
|
|
|
|
|
User->>Mouse: Start drag at (100, 50)
|
|
|
Mouse->>JavaScript: pointerdown event
|
|
|
JavaScript->>JavaScript: Store initial position (pos3=100, pos4=50)
|
|
|
JavaScript->>JavaScript: Setup move/up listeners
|
|
|
|
|
|
User->>Mouse: Move to (110, 60)
|
|
|
Mouse->>JavaScript: pointermove event
|
|
|
JavaScript->>JavaScript: Calculate: pos1=10, pos2=10
|
|
|
JavaScript->>Plant: Update: left += 10px, top += 10px
|
|
|
Plant->>Plant: Render at new position
|
|
|
|
|
|
User->>Mouse: Release at (120, 65)
|
|
|
Mouse->>JavaScript: pointerup event
|
|
|
JavaScript->>JavaScript: Remove listeners
|
|
|
JavaScript->>JavaScript: Reset for next drag
|
|
|
```
|
|
|
|
|
|
**Aqui está o detalhamento do cálculo de movimento:**
|
|
|
1. **Mede** a diferença entre as posições antiga e nova do mouse
|
|
|
2. **Calcula** o quanto mover o elemento com base no movimento do mouse
|
|
|
3. **Atualiza** as propriedades de posição CSS do elemento em tempo real
|
|
|
4. **Armazena** a nova posição como base para o próximo cálculo de movimento
|
|
|
|
|
|
### Representação Visual da Matemática
|
|
|
|
|
|
```mermaid
|
|
|
sequenceDiagram
|
|
|
participant Mouse
|
|
|
participant JavaScript
|
|
|
participant Plant
|
|
|
|
|
|
Mouse->>JavaScript: Move from (100,50) to (110,60)
|
|
|
JavaScript->>JavaScript: Calculate: moved 10px right, 10px down
|
|
|
JavaScript->>Plant: Update position by +10px right, +10px down
|
|
|
Plant->>Plant: Render at new position
|
|
|
```
|
|
|
|
|
|
### A Função stopElementDrag: Limpeza
|
|
|
|
|
|
Adicione a função de limpeza após a chave de fechamento de `elementDrag`:
|
|
|
|
|
|
```javascript
|
|
|
function stopElementDrag() {
|
|
|
// Remove the document-level event listeners
|
|
|
document.onpointerup = null;
|
|
|
document.onpointermove = null;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
**Por que a limpeza é essencial:**
|
|
|
- **Previne** vazamentos de memória causados por listeners de eventos remanescentes
|
|
|
- **Interrompe** o comportamento de arrasto quando o usuário solta a planta
|
|
|
- **Permite** que outros elementos sejam arrastados independentemente
|
|
|
- **Reseta** o sistema para a próxima operação de arrasto
|
|
|
|
|
|
**O que acontece sem a limpeza:**
|
|
|
- Listeners de eventos continuam funcionando mesmo após o fim do arrasto
|
|
|
- O desempenho diminui à medida que listeners não utilizados se acumulam
|
|
|
- Comportamento inesperado ao interagir com outros elementos
|
|
|
- Recursos do navegador são desperdiçados com manipulação de eventos desnecessária
|
|
|
|
|
|
### Entendendo as Propriedades de Posição CSS
|
|
|
|
|
|
Nosso sistema de arrasto manipula duas propriedades CSS principais:
|
|
|
|
|
|
| Propriedade | O que controla | Como usamos |
|
|
|
|-------------|----------------|-------------|
|
|
|
| `top` | Distância da borda superior | Posicionamento vertical durante o arrasto |
|
|
|
| `left` | Distância da borda esquerda | Posicionamento horizontal durante o arrasto |
|
|
|
|
|
|
**Insights importantes sobre as propriedades offset:**
|
|
|
- **`offsetTop`**: Distância atual da borda superior do elemento pai posicionado
|
|
|
- **`offsetLeft`**: Distância atual da borda esquerda do elemento pai posicionado
|
|
|
- **Contexto de posicionamento**: Esses valores são relativos ao ancestral posicionado mais próximo
|
|
|
- **Atualizações em tempo real**: Mudam imediatamente quando modificamos as propriedades CSS
|
|
|
|
|
|
> 🎯 **Filosofia de Design**: Este sistema de arrasto é intencionalmente flexível – não há "zonas de soltura" ou restrições. Os usuários podem posicionar as plantas em qualquer lugar, dando total controle criativo sobre o design do terrário.
|
|
|
|
|
|
## Juntando Tudo: Seu Sistema Completo de Arrasto
|
|
|
|
|
|
Parabéns! Você acabou de construir um sofisticado sistema de arrastar e soltar usando JavaScript puro. Sua função completa `dragElement` agora contém um poderoso closure que gerencia:
|
|
|
|
|
|
**O que seu closure realiza:**
|
|
|
- **Mantém** variáveis de posição privadas para cada planta de forma independente
|
|
|
- **Lida** com todo o ciclo de vida do arrasto do início ao fim
|
|
|
- **Proporciona** movimento suave e responsivo em toda a tela
|
|
|
- **Limpa** recursos adequadamente para evitar vazamentos de memória
|
|
|
- **Cria** uma interface intuitiva e criativa para o design do terrário
|
|
|
|
|
|
### Testando Seu Terrário Interativo
|
|
|
|
|
|
Agora teste seu terrário interativo! Abra seu arquivo `index.html` em um navegador e experimente a funcionalidade:
|
|
|
|
|
|
1. **Clique e segure** qualquer planta para começar a arrastar
|
|
|
2. **Mova o mouse ou dedo** e veja a planta seguir suavemente
|
|
|
3. **Solte** para deixar a planta em sua nova posição
|
|
|
4. **Experimente** diferentes arranjos para explorar a interface
|
|
|
|
|
|
🥇 **Conquista**: Você criou um aplicativo web totalmente interativo usando conceitos fundamentais que desenvolvedores profissionais utilizam diariamente. Essa funcionalidade de arrastar e soltar utiliza os mesmos princípios por trás de uploads de arquivos, quadros kanban e muitas outras interfaces interativas.
|
|
|
|
|
|
### 🔄 **Verificação Pedagógica**
|
|
|
**Compreensão do Sistema Completo**: Verifique sua maestria no sistema de arrasto completo:
|
|
|
- ✅ Como os closures mantêm estado independente para cada planta?
|
|
|
- ✅ Por que a matemática de cálculo de coordenadas é necessária para um movimento suave?
|
|
|
- ✅ O que aconteceria se esquecêssemos de limpar os listeners de eventos?
|
|
|
- ✅ Como esse padrão escala para interações mais complexas?
|
|
|
|
|
|
**Reflexão sobre Qualidade do Código**: Revise sua solução completa:
|
|
|
- **Design modular**: Cada planta tem sua própria instância de closure
|
|
|
- **Eficiência de eventos**: Configuração e limpeza adequadas de listeners
|
|
|
- **Suporte entre dispositivos**: Funciona em desktop e dispositivos móveis
|
|
|
- **Consciente do desempenho**: Sem vazamentos de memória ou cálculos redundantes
|
|
|
|
|
|

|
|
|
|
|
|
---
|
|
|
|
|
|
## Desafio do Agente GitHub Copilot 🚀
|
|
|
|
|
|
Use o modo Agente para completar o seguinte desafio:
|
|
|
|
|
|
**Descrição:** Melhore o projeto do terrário adicionando uma funcionalidade de reset que retorna todas as plantas às suas posições originais com animações suaves.
|
|
|
|
|
|
**Prompt:** Crie um botão de reset que, ao ser clicado, anima todas as plantas de volta às suas posições originais na barra lateral usando transições CSS. A função deve armazenar as posições originais quando a página carregar e mover suavemente as plantas de volta para essas posições em 1 segundo quando o botão de reset for pressionado.
|
|
|
|
|
|
Saiba mais sobre o [modo agente](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode) aqui.
|
|
|
|
|
|
## 🚀 Desafio Adicional: Expanda Seus Conhecimentos
|
|
|
|
|
|
Pronto para levar seu terrário para o próximo nível? Experimente implementar essas melhorias:
|
|
|
|
|
|
**Extensões Criativas:**
|
|
|
- **Clique duplo** em uma planta para trazê-la para frente (manipulação de z-index)
|
|
|
- **Adicione feedback visual** como um brilho sutil ao passar o mouse sobre as plantas
|
|
|
- **Implemente limites** para evitar que as plantas sejam arrastadas para fora do terrário
|
|
|
- **Crie uma função de salvar** que memorize as posições das plantas usando localStorage
|
|
|
- **Adicione efeitos sonoros** ao pegar e posicionar plantas
|
|
|
|
|
|
> 💡 **Oportunidade de Aprendizado**: Cada um desses desafios ensinará novos aspectos de manipulação do DOM, tratamento de eventos e design de experiência do usuário.
|
|
|
|
|
|
## Quiz Pós-Aula
|
|
|
|
|
|
[Quiz pós-aula](https://ff-quizzes.netlify.app/web/quiz/20)
|
|
|
|
|
|
## Revisão & Autoestudo: Aprofundando Seu Conhecimento
|
|
|
|
|
|
Você dominou os fundamentos da manipulação do DOM e closures, mas sempre há mais para explorar! Aqui estão alguns caminhos para expandir seu conhecimento e habilidades.
|
|
|
|
|
|
### Abordagens Alternativas de Arrastar e Soltar
|
|
|
|
|
|
Usamos eventos de ponteiro para máxima flexibilidade, mas o desenvolvimento web oferece várias abordagens:
|
|
|
|
|
|
| Abordagem | Melhor Para | Valor de Aprendizado |
|
|
|
|-----------|-------------|----------------------|
|
|
|
| [API de Arrastar e Soltar HTML](https://developer.mozilla.org/docs/Web/API/HTML_Drag_and_Drop_API) | Uploads de arquivos, zonas formais de arrasto | Compreender capacidades nativas do navegador |
|
|
|
| [Eventos de Toque](https://developer.mozilla.org/docs/Web/API/Touch_events) | Interações específicas para dispositivos móveis | Padrões de desenvolvimento mobile-first |
|
|
|
| Propriedades CSS `transform` | Animações suaves | Técnicas de otimização de desempenho |
|
|
|
|
|
|
### Tópicos Avançados de Manipulação do DOM
|
|
|
|
|
|
**Próximos passos na sua jornada de aprendizado:**
|
|
|
- **Delegação de eventos**: Tratamento eficiente de eventos para múltiplos elementos
|
|
|
- **Intersection Observer**: Detectar quando elementos entram/saem da área de visualização
|
|
|
- **Mutation Observer**: Monitorar mudanças na estrutura do DOM
|
|
|
- **Componentes Web**: Criar elementos de interface reutilizáveis e encapsulados
|
|
|
- **Conceitos de DOM Virtual**: Entender como frameworks otimizam atualizações no DOM
|
|
|
|
|
|
### Recursos Essenciais para Continuar Aprendendo
|
|
|
|
|
|
**Documentação Técnica:**
|
|
|
- [Guia de Eventos de Ponteiro MDN](https://developer.mozilla.org/docs/Web/API/Pointer_events) - Referência abrangente sobre eventos de ponteiro
|
|
|
- [Especificação de Eventos de Ponteiro W3C](https://www.w3.org/TR/pointerevents1/) - Documentação oficial de padrões
|
|
|
- [Mergulho Profundo em Closures JavaScript](https://developer.mozilla.org/docs/Web/JavaScript/Closures) - Padrões avançados de closures
|
|
|
|
|
|
**Compatibilidade de Navegadores:**
|
|
|
- [CanIUse.com](https://caniuse.com/) - Verifique suporte de recursos entre navegadores
|
|
|
- [Dados de Compatibilidade de Navegadores MDN](https://github.com/mdn/browser-compat-data) - Informações detalhadas de compatibilidade
|
|
|
|
|
|
**Oportunidades de Prática:**
|
|
|
- **Construa** um jogo de quebra-cabeça usando mecânicas de arrasto semelhantes
|
|
|
- **Crie** um quadro kanban com gerenciamento de tarefas arrastáveis
|
|
|
- **Projete** uma galeria de imagens com arranjo de fotos arrastáveis
|
|
|
- **Experimente** gestos de toque para interfaces móveis
|
|
|
|
|
|
> 🎯 **Estratégia de Aprendizado**: A melhor maneira de solidificar esses conceitos é através da prática. Experimente criar variações de interfaces arrastáveis – cada projeto ensinará algo novo sobre interação do usuário e manipulação do DOM.
|
|
|
|
|
|
### ⚡ **O Que Você Pode Fazer nos Próximos 5 Minutos**
|
|
|
- [ ] Abra as DevTools do navegador e digite `document.querySelector('body')` no console
|
|
|
- [ ] Experimente alterar o texto de uma página da web usando `innerHTML` ou `textContent`
|
|
|
- [ ] Adicione um listener de evento de clique a qualquer botão ou link em uma página da web
|
|
|
- [ ] Inspecione a estrutura da árvore DOM usando o painel de Elementos
|
|
|
|
|
|
### 🎯 **O Que Você Pode Realizar Nesta Hora**
|
|
|
- [ ] Complete o quiz pós-aula e revise os conceitos de manipulação do DOM
|
|
|
- [ ] Crie uma página web interativa que responda a cliques do usuário
|
|
|
- [ ] Pratique o tratamento de eventos com diferentes tipos de eventos (clique, mouseover, pressionamento de tecla)
|
|
|
- [ ] Construa uma lista de tarefas simples ou contador usando manipulação do DOM
|
|
|
- [ ] Explore a relação entre elementos HTML e objetos JavaScript
|
|
|
|
|
|
### 📅 **Sua Jornada de JavaScript Durante a Semana**
|
|
|
- [ ] Complete o projeto do terrário interativo com funcionalidade de arrastar e soltar
|
|
|
- [ ] Domine a delegação de eventos para tratamento eficiente de eventos
|
|
|
- [ ] Aprenda sobre o loop de eventos e JavaScript assíncrono
|
|
|
- [ ] Pratique closures criando módulos com estado privado
|
|
|
- [ ] Explore APIs modernas do DOM como Intersection Observer
|
|
|
- [ ] Construa componentes interativos sem usar frameworks
|
|
|
|
|
|
### 🌟 **Sua Maestria em JavaScript Durante o Mês**
|
|
|
- [ ] Crie um aplicativo de página única complexo usando JavaScript puro
|
|
|
- [ ] Aprenda um framework moderno (React, Vue ou Angular) e compare com o DOM puro
|
|
|
- [ ] Contribua para projetos de código aberto em JavaScript
|
|
|
- [ ] Domine conceitos avançados como componentes web e elementos personalizados
|
|
|
- [ ] Construa aplicativos web performáticos com padrões de DOM otimizados
|
|
|
- [ ] Ensine outros sobre manipulação do DOM e fundamentos de JavaScript
|
|
|
|
|
|
## 🎯 Sua Linha do Tempo de Maestria em JavaScript e DOM
|
|
|
|
|
|
```mermaid
|
|
|
timeline
|
|
|
title DOM & JavaScript Learning Progression
|
|
|
|
|
|
section Foundation (15 minutes)
|
|
|
DOM Understanding: Element selection methods
|
|
|
: Tree structure navigation
|
|
|
: Property access patterns
|
|
|
|
|
|
section Event Handling (20 minutes)
|
|
|
User Interaction: Pointer event basics
|
|
|
: Event listener setup
|
|
|
: Cross-device compatibility
|
|
|
: Event prevention techniques
|
|
|
|
|
|
section Closures (25 minutes)
|
|
|
Scope Management: Private variable creation
|
|
|
: Function persistence
|
|
|
: State management patterns
|
|
|
: Memory efficiency
|
|
|
|
|
|
section Drag System (30 minutes)
|
|
|
Interactive Features: Coordinate tracking
|
|
|
: Position calculation
|
|
|
: Movement mathematics
|
|
|
: Cleanup procedures
|
|
|
|
|
|
section Advanced Patterns (45 minutes)
|
|
|
Professional Skills: Event delegation
|
|
|
: Performance optimization
|
|
|
: Error handling
|
|
|
: Accessibility considerations
|
|
|
|
|
|
section Framework Understanding (1 week)
|
|
|
Modern Development: Virtual DOM concepts
|
|
|
: State management libraries
|
|
|
: Component architectures
|
|
|
: Build tool integration
|
|
|
|
|
|
section Expert Level (1 month)
|
|
|
Advanced DOM APIs: Intersection Observer
|
|
|
: Mutation Observer
|
|
|
: Custom Elements
|
|
|
: Web Components
|
|
|
```
|
|
|
|
|
|
### 🛠️ Resumo do Seu Kit de Ferramentas JavaScript
|
|
|
|
|
|
Após completar esta lição, você agora possui:
|
|
|
- **Domínio do DOM**: Seleção de elementos, manipulação de propriedades e navegação na árvore
|
|
|
- **Expertise em Eventos**: Tratamento de interações entre dispositivos com eventos de ponteiro
|
|
|
- **Compreensão de Closures**: Gerenciamento de estado privado e persistência de funções
|
|
|
- **Sistemas Interativos**: Implementação completa de arrastar e soltar do zero
|
|
|
- **Consciência de Desempenho**: Limpeza adequada de eventos e gerenciamento de memória
|
|
|
- **Padrões Modernos**: Técnicas de organização de código usadas no desenvolvimento profissional
|
|
|
- **Experiência do Usuário**: Criação de interfaces intuitivas e responsivas
|
|
|
|
|
|
**Habilidades Profissionais Adquiridas**: Você construiu recursos usando as mesmas técnicas que:
|
|
|
- **Quadros Kanban/Trello**: Arrastar cartões entre colunas
|
|
|
- **Sistemas de upload de arquivos**: Manipulação de arquivos arrastáveis
|
|
|
- **Galerias de imagens**: Interfaces de arranjo de fotos
|
|
|
- **Aplicativos móveis**: Padrões de interação baseados em toque
|
|
|
|
|
|
**Próximo Nível**: Você está pronto para explorar frameworks modernos como React, Vue ou Angular que se baseiam nesses conceitos fundamentais de manipulação do DOM!
|
|
|
|
|
|
## Tarefa
|
|
|
|
|
|
[Trabalhe um pouco mais com o DOM](assignment.md)
|
|
|
|
|
|
---
|
|
|
|
|
|
**Aviso Legal**:
|
|
|
Este documento foi traduzido usando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automatizadas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte autoritativa. Para informações críticas, recomenda-se a tradução profissional humana. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução. |