🎯 Lezione 10: Gestione Eventi JavaScript
Scopri come gestire eventi del browser: click, input, submit e molto altro
Cos’è un Evento?
Un evento è un’azione o un’occorrenza che accade nel browser, come un click del mouse, la pressione di un tasto, il caricamento di una pagina. JavaScript può “ascoltare” questi eventi e reagire di conseguenza.
Metodo Moderno: addEventListener
js
const bottone = document.querySelector('button');
// Sintassi: elemento.addEventListener(evento, funzione)
bottone.addEventListener('click', function(evento) {
console.log('Bottone è stato cliccato!');
console.log('Elemento cliccato:', evento.target);
console.log('Coordinata X del click:', evento.clientX);
console.log('Coordinata Y del click:', evento.clientY);
});
// Con arrow function
bottone.addEventListener('click', (evento) => {
console.log('Click con arrow function');
});
// Con funzione predefinita
function gestisciClick(evento) {
console.log('Click gestito da funzione separata');
}
bottone.addEventListener('click', gestisciClick);
Eventi Principali del Browser
js
// Eventi del mouse
bottone.addEventListener('click', () => console.log('Click'));
bottone.addEventListener('dblclick', () => console.log('Doppio click'));
bottone.addEventListener('mouseenter', () => console.log('Mouse entrato'));
bottone.addEventListener('mouseleave', () => console.log('Mouse uscito'));
bottone.addEventListener('mousemove', (e) => console.log(`Mouse: ${e.clientX}, ${e.clientY}`));
// Eventi della tastiera
document.addEventListener('keydown', (e) => {
console.log('Tasto premuto:', e.key);
console.log('Codice tasto:', e.code);
});
document.addEventListener('keyup', (e) => {
console.log('Tasto rilasciato:', e.key);
});
// Eventi del form
const input = document.querySelector('input');
input.addEventListener('focus', () => console.log('Input in focus'));
input.addEventListener('blur', () => console.log('Input perso focus'));
input.addEventListener('input', (e) => console.log('Testo cambiato:', e.target.value));
input.addEventListener('change', (e) => console.log('Valore cambiato:', e.target.value));
// Eventi di caricamento
document.addEventListener('DOMContentLoaded', () => {
console.log('DOM completamente caricato e pronto');
});
window.addEventListener('load', () => {
console.log('Pagina completamente caricata (include immagini)');
});
window.addEventListener('beforeunload', (e) => {
e.preventDefault();
e.returnValue = ''; // Mostra avviso di conferma
});
Prevenire Comportamenti Predefiniti
js
// Prevenire l'invio di un form
const form = document.querySelector('form');
form.addEventListener('submit', function(evento) {
evento.preventDefault(); // Impedisce il ricaricamento della pagina
console.log('Form inviato ma pagina non ricaricata!');
// Qui puoi gestire i dati del form
const dati = new FormData(this);
console.log('Dati form:', Object.fromEntries(dati));
});
// Prevenire il comportamento di un link
const link = document.querySelector('a');
link.addEventListener('click', function(evento) {
evento.preventDefault(); // Impedisce la navigazione
console.log('Link cliccato ma navigazione bloccata');
// Qui puoi fare qualcos'altro invece di navigare
alert('Navigazione bloccata!');
});
// Prevenire il menu contestuale (tasto destro)
document.addEventListener('contextmenu', function(evento) {
evento.preventDefault();
console.log('Menu contestuale disabilitato');
});
Propagazione degli Eventi: Bubbling e Capturing
js
// HTML: <div id="genitore"><button id="figlio">Cliccami</button></div>
const genitore = document.getElementById('genitore');
const figlio = document.getElementById('figlio');
// BUBBLING (default) - dall'interno verso l'esterno
figlio.addEventListener('click', () => console.log('Figlio cliccato'));
genitore.addEventListener('click', () => console.log('Genitore cliccato'));
// Output quando clicchi il figlio: "Figlio cliccato" → "Genitore cliccato"
// CAPTURING - dall'esterno verso l'interno
genitore.addEventListener('click', () => console.log('Genitore (capturing)'), true);
figlio.addEventListener('click', () => console.log('Figlio (capturing)'), true);
// Output: "Genitore (capturing)" → "Figlio (capturing)"
// Fermare la propagazione
figlio.addEventListener('click', function(evento) {
evento.stopPropagation(); // Ferma la propagazione
console.log('Click sul figlio - propagazione fermata');
});
Delegazione degli Eventi
js
// Invece di aggiungere event listener a ogni elemento,
// aggiungine uno al genitore e usa event.target
const lista = document.getElementById('lista');
// DELEGAZIONE CORRETTA
lista.addEventListener('click', function(evento) {
// Controlla se il click è su un elemento LI
if (evento.target.tagName === 'LI') {
evento.target.classList.toggle('selezionato');
console.log('Elemento selezionato:', evento.target.textContent);
}
// Controlla se il click è su un bottone dentro LI
if (evento.target.tagName === 'BUTTON') {
const item = evento.target.parentElement;
item.remove();
console.log('Elemento rimosso');
}
});
// Questo funziona anche per elementi aggiunti dinamicamente!
function aggiungiElemento() {
const nuovoLi = document.createElement('li');
nuovoLi.innerHTML = `Nuovo elemento <button>Rimuovi</button>`;
lista.appendChild(nuovoLi);
// Non serve aggiungere event listener - la delegazione funziona già!
}
🎯 Esercizio Pratico: Todo List Interattiva
Obiettivo: Crea una todo list completa con tutte le funzionalità
html + js
<!-- HTML -->
<div id="todoApp">
<h2>📝 La Mia Todo List</h2>
<div class="input-group">
<input type="text" id="todoInput" placeholder="Cosa devi fare?">
<button id="aggiungiBtn">Aggiungi</button>
</div>
<ul id="todoList"></ul>
<div class="controlli">
<button id="cancellaCompletati">Cancella Completati</button>
<button id="cancellaTutti">Cancella Tutti</button>
<span id="contatore">0 task</span>
</div>
</div>
<script>
class TodoApp {
constructor() {
this.todos = JSON.parse(localStorage.getItem('todos')) || [];
this.init();
}
init() {
this.bindEvents();
this.render();
this.aggiornaContatore();
}
bindEvents() {
// Aggiungi todo con click
document.getElementById('aggiungiBtn').addEventListener('click', () => this.aggiungiTodo());
// Aggiungi todo con Enter
document.getElementById('todoInput').addEventListener('keypress', (e) => {
if (e.key === 'Enter') this.aggiungiTodo();
});
// Delegazione eventi per la lista
document.getElementById('todoList').addEventListener('click', (e) => {
if (e.target.classList.contains('completa')) {
this.toggleCompleta(parseInt(e.target.dataset.id));
} else if (e.target.classList.contains('elimina')) {
this.eliminaTodo(parseInt(e.target.dataset.id));
}
});
// Pulsanti controllo
document.getElementById('cancellaCompletati').addEventListener('click', () => this.cancellaCompletati());
document.getElementById('cancellaTutti').addEventListener('click', () => this.cancellaTutti());
}
aggiungiTodo() {
const input = document.getElementById('todoInput');
const testo = input.value.trim();
if (testo) {
this.todos.push({
id: Date.now(),
testo: testo,
completato: false
});
input.value = '';
this.salva();
this.render();
this.aggiornaContatore();
}
}
toggleCompleta(id) {
this.todos = this.todos.map(todo =>
todo.id === id ? {...todo, completato: !todo.completato} : todo
);
this.salva();
this.render();
this.aggiornaContatore();
}
eliminaTodo(id) {
this.todos = this.todos.filter(todo => todo.id !== id);
this.salva();
this.render();
this.aggiornaContatore();
}
cancellaCompletati() {
this.todos = this.todos.filter(todo => !todo.completato);
this.salva();
this.render();
this.aggiornaContatore();
}
cancellaTutti() {
if (confirm('Sei sicuro di voler cancellare tutti i task?')) {
this.todos = [];
this.salva();
this.render();
this.aggiornaContatore();
}
}
render() {
const lista = document.getElementById('todoList');
lista.innerHTML = this.todos.map(todo => `
<li class="${todo.completato ? 'completato' : ''}">
<span>${todo.testo}</span>
<div>
<button class="completa" data-id="${todo.id}">
${todo.completato ? '❌' : '✅'}
</button>
<button class="elimina" data-id="${todo.id}">🗑️</button>
</div>
</li>
`).join('');
}
aggiornaContatore() {
const totale = this.todos.length;
const completati = this.todos.filter(todo => todo.completato).length;
document.getElementById('contatore').textContent =
`${completati}/${totale} completati`;
}
salva() {
localStorage.setItem('todos', JSON.stringify(this.todos));
}
}
// Inizializza l'app quando il DOM è pronto
document.addEventListener('DOMContentLoaded', () => {
new TodoApp();
});
</script>
<style>
.completato span { text-decoration: line-through; opacity: 0.6; }
.input-group { margin: 20px 0; display: flex; gap: 10px; }
.controlli { margin-top: 20px; display: flex; gap: 10px; align-items: center; }
#todoList { list-style: none; padding: 0; }
#todoList li {
display: flex; justify-content: space-between;
padding: 10px; margin: 5px 0; background: #f5f5f5;
border-radius: 5px;
}
</style>
Sfida avanzata: Aggiungi queste funzionalità:
- Modifica dei task esistenti (doppio click per editare)
- Filtri per vedere solo i task completati/non completati
- Drag & drop per riordinare i task
- Scadenze e promemoria per i task