Mert Özen Her Satırda Daha İleri
Frontend JavaScript Temel — #15

JavaScript Event'leri: addEventListener ile Tıklama, Klavye ve Input

Mert Özen 3 Kas 2026 7 dk 5 görüntülenme
JavaScript Event'leri: addEventListener ile Tıklama, Klavye ve Input

addEventListener ile click, input, keydown ve submit event'lerini dinliyor; event object'indeki target ve key'i, preventDefault'u, removeEventListener'ı ve inline onclick'in neden önerilmediğini öğreniyoruz.

Sürüm notu: Bu yazıdaki kodlar ES2026 ve güncel tarayıcılar (Chrome, Edge, Firefox, Safari) içindir.

Önce Tahmin Et

Bu dosyayı kaydedip aç, konsolu da açık tut:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Predict</title>
</head>
<body>
  <button id="button">Click me</button>
  <script>
    function greet() {
      console.log("Hello!");
    }

    const button = document.getElementById("button");
    button.addEventListener("click", greet());
  </script>
</body>
</html>

İki soru: sayfa açıldığında, sen daha hiçbir şeye dokunmadan konsolda ne görürsün? Butona üç kez tıkladığında ne olur? Okumaya devam etmeden önce bir tahmin yap. Cevap, addEventListener'ın ne beklediğini konuştuğumuz bölümde.

Event Nedir?

Kapı zilini düşün. Biri gelecek mi diye bütün gün kapının önünde beklemezsin. Zil çalınca kalkıp kapıyı açarsın. Event'ler de tam olarak böyle çalışır. Tarayıcı sayfada olup biten her şeyi izler: bir tıklama, bir tuşa basılması, bir kutuya yazı yazılması, bir formun gönderilmesi. Bunların her birine event denir. Sen de tarayıcıya "şu element için şu event olursa, şu fonksiyonu çalıştır" dersin.

Buradaki fonksiyon, daha önce fonksiyonlar yazısında ilk kez gördüğümüz callback'in ta kendisi. Onu sen çağırmazsın; tarayıcıya teslim edersin, tarayıcı da zamanı gelince çağırır. Kodun yukarıdan aşağı bir kez akıp bitmez, kullanıcı bir şey yaptıkça yeniden canlanır.

addEventListener ile Dinlemek

Bir sayaçla başlayalım. Kaydet, aç ve butona birkaç kez tıkla:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Counter</title>
</head>
<body>
  <button id="increase">Increase</button>
  <p>Clicks: <span id="count">0</span></p>
  <script>
    const button = document.getElementById("increase");
    const countArea = document.getElementById("count");
    let counter = 0;

    function increase() {
      counter = counter + 1;
      countArea.textContent = counter;
    }

    button.addEventListener("click", increase);
    button.addEventListener("click", () => console.log("Clicked"));
  </script>
</body>
</html>

addEventListener üç şeyi bir araya getirir: dinlenen element (button), event'in adı ("click") ve event olduğunda çalışacak fonksiyon. Aynı element'e istediğin kadar listener ekleyebilirsin; yukarıda tek tıklamayla hem sayı artıyor hem de konsola yazı düşüyor. Listener'lar eklendikleri sırayla çalışır.

Şimdi baştaki sorunun cevabı. Dikkat edersen sayaç örneğinde fonksiyonu parantezsiz verdik: increase. Tahmin örneğinde ise greet() yazdık. Parantez koyduğun anda fonksiyonu o satırda çağırmış olursun. Bu yüzden sayfa açılır açılmaz konsolda bir kez "Hello!" görürsün. greet bir şey döndürmediği için sonuç undefined olur ve addEventListener'a fonksiyon yerine undefined gider. Tarayıcı hata vermez, sadece dinleyecek bir şey bulamaz. Üç kez tıklasan da konsola başka hiçbir şey yazılmaz. Kural şu: fonksiyonu çağırma, kendisini ver.

Event Object'i: Ne Oldu, Nerede Oldu?

Tarayıcı listener'ını çağırırken ona bir şey daha verir: ilk parametre olarak, olan bitenin bütün ayrıntılarını taşıyan bir event object'i.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Event Object</title>
</head>
<body>
  <button class="color">Red</button>
  <button class="color">Green</button>
  <button class="color">Blue</button>
  <p id="choice">No choice yet.</p>
  <script>
    const choice = document.getElementById("choice");

    function pickColor(event) {
      console.log(event.type);   // "click"
      console.log(event.target); // tıklanan buton
      choice.textContent = "You picked: " + event.target.textContent;
    }

    document.querySelectorAll(".color").forEach((button) => {
      button.addEventListener("click", pickColor);
    });
  </script>
</body>
</html>

Üç buton aynı fonksiyonu paylaşıyor ama hangisine tıklandığını event.target sayesinde biliyoruz. target, event'in gerçekleştiği element'tir. event.type ise event'in adını verir. Parametrenin adı önemli değil; kodlarda event, e ya da evt görürsün, hepsi aynı object.

Tıklamanın ekranda nerede olduğu (clientX, clientY) ya da basılan tuş gibi bilgiler de bu object'te durur. Event'in sayfada bir element'ten diğerine nasıl ilerlediğini ve target'ın akrabası currentTarget'ı Orta seride detaylandıracağız.

Klavye ve Yazı: input ve keydown

input: Her değişiklikte

Bir metin kutusunu dinlemek için en kullanışlı event input'tur. Kutunun değeri her değiştiğinde, yani her harf yazıldığında ya da silindiğinde çalışır:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Live Preview</title>
</head>
<body>
  <input id="message" placeholder="Type something...">
  <p id="preview"></p>
  <p id="counter">0 / 50</p>
  <script>
    const message = document.getElementById("message");
    const preview = document.getElementById("preview");
    const counter = document.getElementById("counter");

    message.addEventListener("input", (event) => {
      const text = event.target.value;
      preview.textContent = text;
      counter.textContent = text.length + " / 50";
    });

    message.addEventListener("keydown", (event) => {
      console.log("Key pressed:", event.key);
      if (event.key === "Escape") {
        message.value = "";
        preview.textContent = "";
        counter.textContent = "0 / 50";
      }
    });
  </script>
</body>
</html>

Kutuya yazdıkça önizleme ve karakter sayısı anında güncelleniyor. Kutunun içindeki metni value property'si verir. Önizlemeyi textContent ile yazdığımıza dikkat et; daha önce gördüğümüz XSS riskini burada da göz ardı etmiyoruz. Bir de change event'i var; o, kullanıcı kutudan çıkıp değeri onayladığında bir kez çalışır. Canlı tepki istiyorsan input, son hâli yeterliyse change.

keydown: Hangi tuşa basıldı?

keydown, bir tuşa basıldığı anda çalışır. Basılan tuşu event.key söyler: harfler için "a" ya da "A", özel tuşlar için "Enter", "Escape", "ArrowUp", "Backspace" gibi isimler. Yukarıdaki örnekte Escape'e basınca kutu temizleniyor. Konsoldaki çıktıya bakarak birkaç tuşun adını öğrenebilirsin.

Sayfanın tamamında geçerli bir kısayol istiyorsan listener'ı document'a eklersin: document.addEventListener("keydown", ...). Klavye düzeninden bağımsız fiziksel tuş için event.code da var, ama çoğu iş için event.key yeterli. Eski kodlarda gördüğün keypress artık kullanımdan kalktı; yerine keydown kullan.

Varsayılan Davranışı Durdurmak: preventDefault

Bazı element'lerin tarayıcıdan gelen hazır bir davranışı vardır. Bir linke tıklayınca başka sayfaya gidilir, bir form gönderilince sayfa yenilenir. event.preventDefault() bu varsayılan davranışı iptal eder:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>preventDefault</title>
</head>
<body>
  <a id="link" href="https://developer.mozilla.org">Go to MDN</a>
  <form id="form">
    <input id="name" placeholder="Your name">
    <button>Send</button>
  </form>
  <p id="result"></p>
  <script>
    document.getElementById("link").addEventListener("click", (event) => {
      event.preventDefault();
      console.log("The link was clicked but the page didn't change.");
    });

    document.getElementById("form").addEventListener("submit", (event) => {
      event.preventDefault();
      const name = document.getElementById("name").value;
      document.getElementById("result").textContent = "Hello, " + name;
    });
  </script>
</body>
</html>

submit event'ini butona değil forma eklediğimize dikkat et. Böylece kullanıcı butona tıklasa da kutudayken Enter'a bassa da aynı kod çalışır. preventDefault olmasaydı sayfa yenilenir ve yazdığın mesaj bir anlığına bile görünmezdi. Formlarla çalışmanın bütün ayrıntılarını bir sonraki yazıya bırakıyoruz.

Dinlemeyi Bırakmak: removeEventListener

Bir listener'a artık ihtiyacın kalmadıysa onu kaldırabilirsin. Bu butona sadece üç kez oy verilebilsin:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Three Votes</title>
</head>
<body>
  <button id="vote">Vote</button>
  <script>
    const voteButton = document.getElementById("vote");
    let votes = 0;

    function vote() {
      votes = votes + 1;
      console.log("Votes:", votes);
      if (votes === 3) {
        voteButton.removeEventListener("click", vote);
        voteButton.textContent = "No votes left";
      }
    }

    voteButton.addEventListener("click", vote);
  </script>
</body>
</html>

removeEventListener'ın çalışması için ona, eklerken verdiğin fonksiyonun aynısını vermen gerekir. Aynısı derken içi aynı yazılmış başka bir fonksiyonu değil, aynı referansı kastediyorum. Daha önce object'ler yazısında gördüğümüz referans mantığı burada da geçerli: aynı görünen iki ayrı fonksiyon, iki ayrı object'tir. Bu yüzden ileride kaldırmayı düşündüğün bir listener'ı adı olan bir fonksiyon ya da bir değişkende saklanan bir fonksiyon olarak yaz. Tek seferlik listener'lar için bir kısayol da var; onu ilerleyen yazılarda göreceğiz.

Sık Düşülen Tuzaklar

Inline onclick ile yazmak

Eski örneklerde sık görürsün:

<button onclick="greet()">Click me</button>

Çalışır ama önerilmez. HTML ile JavaScript'i birbirine karıştırır; davranışı değiştirmek için iki dosyayı birden düzenlersin. Çağrılan fonksiyonun global olması gerekir. Birçok sitenin güvenlik ayarı (Content Security Policy) satır içi kodu tamamen engeller. JavaScript tarafındaki onclick property'si de tek bir yer tutar. Tahmin dosyasını açıp konsola yapıştır, sonra butona tıkla:

const btn = document.querySelector("button");
btn.onclick = () => console.log("First");
btn.onclick = () => console.log("Second"); // birinciyi siler

btn.addEventListener("click", () => console.log("Third"));
btn.addEventListener("click", () => console.log("Fourth")); // ikisi de çalışır

Tıkladığında "Second", "Third" ve "Fourth" görürsün; "First" sessizce kaybolmuştur. addEventListener üst üste yazmaz, ekler.

Event adının başına "on" koymak

addEventListener("onclick", ...) hata vermez ama hiçbir zaman çalışmaz, çünkü öyle bir event yok. Event'in adı "click"; on öneki sadece HTML attribute'larında ve property'lerde kullanılır.

Element yokken listener eklemek

Script element'ten önce çalışırsa getElementById null döner ve null.addEventListener bir TypeError fırlatır. Daha önce gördüğümüz çözüm burada da geçerli: script'i body'nin sonuna koy ya da defer kullan.

Küçük Bir Deneme

★☆☆ Sayaç örneğine bir "Reset" butonu ekle. Tıklanınca sayaç sıfıra dönsün ve ekrandaki sayı da güncellensin.

★★☆ Çalıştırmadan önce tahmin et: bu kodu tahmin dosyasının konsoluna yapıştırıp butona iki kez tıklarsan konsolda kaç satır görürsün? Sonra dene.

const btn = document.querySelector("button");
btn.addEventListener("click", () => console.log("Click"));
btn.removeEventListener("click", () => console.log("Click"));

★★★ Sayfaya bir kutu (div) koy. Ok tuşlarıyla ("ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight") kutunun yerini 10 piksel değiştir. İpucu: listener'ı document'a ekle, kutuya position: relative ver ve style.top ile style.left değerlerini bir değişkende tuttuğun sayılarla güncelle.

Event'lerle kullanıcıyı dinlemeyi öğrendik. Kullanıcının sayfaya en çok veri girdiği yer ise formlar. Bir sonraki yazıda form alanlarının değerlerini okumayı, gönderimi yakalamayı ve kullanıcıya anlaşılır hata mesajları göstermeyi göreceğiz.