addEventListener, olay türleri, olay nesnesi, köpürme ve delegasyon.
Olaylar (events) kullanıcının sayfayla etkileşimini temsil eder. Tıklama, klavye basma, form gönderme, sayfa yüklenme gibi yüzlerce olay türü vardır.
onclick bir elemente yalnızca tek bir işleyici bağlar, ikincisi birincinin üzerine yazar. addEventListener aynı olaya birden fazla işleyici bağlayabilir. Modern JS'te addEventListener kullanın.
Bir elementin olayı tetiklenince, olay önce yukarıdan aşağıya capturing aşamasıyla iner, sonra yukarıya doğru bubbling aşamasıyla yayılır. stopPropagation() bu yayılmayı durdurur.
100 liste öğesi için 100 ayrı listener yerine, üst elemana tek bir listener koyup e.target ile hangi öğeye tıklandığını anlamak çok daha verimlidir. Dinamik olarak eklenen elementler için zorunludur.
Debounce kullanıcı yazmayı bıraktıktan sonra belirli bir süre bekleyip çalışır — arama kutuları için ideal. Throttle belirli aralıklarla çalışır — scroll ve resize olayları için kullanılır.
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<style>
body { font-family: sans-serif; padding: 20px; }
.kutu { width: 200px; height: 100px; background: #6366f1; color: white; display: flex; align-items: center; justify-content: center; border-radius: 12px; cursor: pointer; user-select: none; margin: 12px 0; font-weight: bold; }
.log { background: #1e293b; color: #94a3b8; padding: 12px; border-radius: 8px; font-family: monospace; font-size: 12px; height: 120px; overflow-y: auto; margin: 12px 0; }
.log .zaman { color: #6366f1; }
button { padding: 8px 16px; background: #6366f1; color: white; border: none; border-radius: 8px; cursor: pointer; margin: 4px; }
input { padding: 8px; border: 1px solid #e2e8f0; border-radius: 8px; width: 200px; }
</style>
</head>
<body>
<div class="kutu" id="tur-kutu">Tıkla / Sürükle / Hover</div>
<div class="log" id="log"></div>
<input id="arama" type="text" placeholder="Yazmaya başlayın...">
<div id="arama-sonuc"></div>
<div id="buton-grup">
<button data-aksiyon="kaydet">💾 Kaydet</button>
<button data-aksiyon="sil">🗑 Sil</button>
<button data-aksiyon="duzenle">✏ Düzenle</button>
</div>
<script>
function logEkle(mesaj) {
const log = document.getElementById('log');
const zaman = new Date().toLocaleTimeString('tr-TR');
log.innerHTML += `<div><span class="zaman">[${zaman}]</span> ${mesaj}</div>`;
log.scrollTop = log.scrollHeight;
}
const kutu = document.getElementById('tur-kutu');
// ── Mouse Olayları ──
kutu.addEventListener('click', e => logEkle(`click — (${e.clientX}, ${e.clientY})`));
kutu.addEventListener('dblclick', () => logEkle('çift tıklama!'));
kutu.addEventListener('mouseenter', () => { kutu.style.background = '#4f46e5'; logEkle('mouse girdi'); });
kutu.addEventListener('mouseleave', () => { kutu.style.background = '#6366f1'; logEkle('mouse çıktı'); });
kutu.addEventListener('mousedown', e => logEkle(`mousedown — tuş: ${e.button}`)); // 0=sol, 1=orta, 2=sağ
kutu.addEventListener('contextmenu', e => { e.preventDefault(); logEkle('sağ tık'); });
// ── Klavye Olayları ──
document.addEventListener('keydown', e => {
if (e.key === 'Escape') logEkle('ESC basıldı');
if (e.ctrlKey && e.key === 's') { e.preventDefault(); logEkle('Ctrl+S — Kaydet!'); }
if (e.altKey && e.key === 'k') logEkle('Alt+K basıldı');
});
// ── Input Olayları ──
const aramaDegisim = debounce(function(e) {
document.getElementById('arama-sonuc').textContent =
`Aranan: "${e.target.value}" (${e.target.value.length} karakter)`;
}, 400);
document.getElementById('arama').addEventListener('input', aramaDegisim);
// ── Event Delegation (Olay Delege) ──
// Her butona ayrı listener yerine, üst elemana tek listener
document.getElementById('buton-grup').addEventListener('click', function(e) {
const btn = e.target.closest('button');
if (!btn) return;
const aksiyon = btn.dataset.aksiyon;
logEkle(`Butona tıklandı: ${aksiyon}`);
});
// ── Bubbling ve stopPropagation ──
document.addEventListener('click', () => logEkle('document click (bubbling)'));
kutu.addEventListener('click', e => {
e.stopPropagation(); // Yukarı yayılmayı durdur
logEkle('kutu click — yayılma durduruldu');
});
// ── Debounce Yardımcı ──
function debounce(fn, gecikme) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), gecikme);
};
}
// ── Scroll Olayı ──
window.addEventListener('scroll', debounce(() => {
logEkle(`Scroll: ${window.scrollY}px`);
}, 200));
// ── Tek Sefer Çalış ──
kutu.addEventListener('animationend', () => {
logEkle('Animasyon bitti');
}, { once: true }); // once: true — sadece bir kez
</script>
</body>
</html>