אירועים (Events)

אירועים הם פעולות שקורות בדף - לחיצות, הקלדות, תנועות עכבר ועוד. JavaScript מאפשרת להגיב לאירועים אלה.


מה זה אירוע?

אירוע הוא כל פעולה שקורית בדף: - לחיצת עכבר - הקלדה במקלדת - טעינת הדף - הזזת העכבר - שינוי גודל החלון - ועוד...


הוספת Event Listener

addEventListener (מומלץ!)

const button = document.querySelector("#myButton");

button.addEventListener("click", function() {
    console.log("לחצת על הכפתור!");
});

// עם arrow function
button.addEventListener("click", () => {
    console.log("לחצת על הכפתור!");
});

// עם פונקציה נפרדת
function handleClick() {
    console.log("לחצת על הכפתור!");
}
button.addEventListener("click", handleClick);

שיטות ישנות (פחות מומלצות)

// onclick property
button.onclick = function() {
    console.log("לחצת!");
};

// inline HTML (לא מומלץ!)
// <button onclick="handleClick()">לחץ</button>

סוגי אירועים נפוצים

אירועי עכבר

element.addEventListener("click", handler);      // לחיצה
element.addEventListener("dblclick", handler);   // לחיצה כפולה
element.addEventListener("mouseenter", handler); // עכבר נכנס
element.addEventListener("mouseleave", handler); // עכבר יוצא
element.addEventListener("mousemove", handler);  // עכבר זז
element.addEventListener("mousedown", handler);  // לחצן עכבר נלחץ
element.addEventListener("mouseup", handler);    // לחצן עכבר שוחרר

אירועי מקלדת

document.addEventListener("keydown", handler);   // מקש נלחץ
document.addEventListener("keyup", handler);     // מקש שוחרר
document.addEventListener("keypress", handler);  // מקש נלחץ (deprecated)

אירועי טפסים

input.addEventListener("focus", handler);   // קיבל פוקוס
input.addEventListener("blur", handler);    // איבד פוקוס
input.addEventListener("input", handler);   // ערך השתנה
input.addEventListener("change", handler);  // ערך השתנה (סיום)
form.addEventListener("submit", handler);   // טופס נשלח

אירועי דף

window.addEventListener("load", handler);          // הדף נטען
document.addEventListener("DOMContentLoaded", handler); // DOM מוכן
window.addEventListener("resize", handler);        // גודל השתנה
window.addEventListener("scroll", handler);        // גלילה

Event Object

כל handler מקבל אובייקט event עם מידע על האירוע:

button.addEventListener("click", function(event) {
    console.log(event.type);    // "click"
    console.log(event.target);  // האלמנט שנלחץ
    console.log(event.currentTarget); // האלמנט עם הlistener
});

// קיצור נפוץ
button.addEventListener("click", (e) => {
    console.log(e.target);
});

מידע על עכבר

element.addEventListener("click", (e) => {
    console.log(e.clientX, e.clientY);  // מיקום בחלון
    console.log(e.pageX, e.pageY);      // מיקום בדף
    console.log(e.button);              // איזה כפתור (0=שמאל)
});

מידע על מקלדת

document.addEventListener("keydown", (e) => {
    console.log(e.key);      // "Enter", "a", "ArrowUp"
    console.log(e.code);     // "Enter", "KeyA", "ArrowUp"
    console.log(e.shiftKey); // האם Shift לחוץ
    console.log(e.ctrlKey);  // האם Ctrl לחוץ
    console.log(e.altKey);   // האם Alt לחוץ

    if (e.key === "Enter") {
        console.log("לחצת Enter!");
    }
});

preventDefault - מניעת ברירת מחדל

// מניעת שליחת טופס
form.addEventListener("submit", (e) => {
    e.preventDefault();  // הדף לא יתרענן
    console.log("הטופס נקלט!");
    // עיבוד הנתונים...
});

// מניעת פתיחת קישור
link.addEventListener("click", (e) => {
    e.preventDefault();
    console.log("מנעתי מעבר לקישור");
});

stopPropagation - עצירת התפשטות

אירועים "מבעבעים" למעלה בעץ ה-DOM:

/*
<div id="outer">
    <div id="inner">
        <button id="btn">לחץ</button>
    </div>
</div>
*/

const outer = document.querySelector("#outer");
const inner = document.querySelector("#inner");
const btn = document.querySelector("#btn");

outer.addEventListener("click", () => console.log("outer"));
inner.addEventListener("click", () => console.log("inner"));
btn.addEventListener("click", (e) => {
    console.log("button");
    e.stopPropagation();  // עוצר את ההתפשטות
});

// לחיצה על הכפתור תדפיס רק "button"
// בלי stopPropagation היה מדפיס: "button", "inner", "outer"

Event Delegation

טכניקה יעילה - הוספת listener אחד להורה במקום לכל ילד:

/*
<ul id="list">
    <li>פריט 1</li>
    <li>פריט 2</li>
    <li>פריט 3</li>
</ul>
*/

const list = document.querySelector("#list");

// ❌ לא יעיל - listener לכל li
document.querySelectorAll("li").forEach(li => {
    li.addEventListener("click", () => {
        console.log(li.textContent);
    });
});

// ✅ יעיל - listener אחד על הרשימה
list.addEventListener("click", (e) => {
    if (e.target.tagName === "LI") {
        console.log(e.target.textContent);
    }
});

// יתרון: עובד גם על פריטים שיתווספו בעתיד!

הסרת Event Listener

function handleClick() {
    console.log("לחצת!");
}

// הוספה
button.addEventListener("click", handleClick);

// הסרה
button.removeEventListener("click", handleClick);

// ❌ לא עובד עם פונקציה אנונימית
button.addEventListener("click", () => console.log("שלום"));
button.removeEventListener("click", () => console.log("שלום")); // לא אותה פונקציה!

once - הרצה פעם אחת

button.addEventListener("click", () => {
    console.log("זה יקרה רק פעם אחת!");
}, { once: true });

דוגמאות מעשיות

Toggle Button

const toggleBtn = document.querySelector("#toggle");
const content = document.querySelector("#content");

toggleBtn.addEventListener("click", () => {
    content.classList.toggle("hidden");
    toggleBtn.textContent = content.classList.contains("hidden") 
        ? "הצג" 
        : "הסתר";
});

Form Validation

const form = document.querySelector("#form");
const emailInput = document.querySelector("#email");
const errorMsg = document.querySelector("#error");

form.addEventListener("submit", (e) => {
    e.preventDefault();

    const email = emailInput.value;

    if (!email.includes("@")) {
        errorMsg.textContent = "אימייל לא תקין";
        emailInput.classList.add("invalid");
    } else {
        errorMsg.textContent = "";
        emailInput.classList.remove("invalid");
        console.log("הטופס נשלח!");
    }
});

Character Counter

const textarea = document.querySelector("#message");
const counter = document.querySelector("#counter");
const maxLength = 100;

textarea.addEventListener("input", () => {
    const remaining = maxLength - textarea.value.length;
    counter.textContent = `נותרו ${remaining} תווים`;

    if (remaining < 10) {
        counter.style.color = "red";
    } else {
        counter.style.color = "black";
    }
});

Keyboard Shortcuts

document.addEventListener("keydown", (e) => {
    // Ctrl+S
    if (e.ctrlKey && e.key === "s") {
        e.preventDefault();
        console.log("שומר...");
    }

    // Escape
    if (e.key === "Escape") {
        console.log("סוגר...");
    }
});

Drag & Drop (בסיסי)

const draggable = document.querySelector("#draggable");
const dropzone = document.querySelector("#dropzone");

draggable.addEventListener("dragstart", (e) => {
    e.dataTransfer.setData("text/plain", draggable.id);
});

dropzone.addEventListener("dragover", (e) => {
    e.preventDefault();  // מאפשר drop
});

dropzone.addEventListener("drop", (e) => {
    e.preventDefault();
    const id = e.dataTransfer.getData("text/plain");
    const element = document.getElementById(id);
    dropzone.appendChild(element);
});

דוגמה מלאה - Todo List

HTML

<div id="app">
    <h1>רשימת משימות</h1>
    <form id="todoForm">
        <input type="text" id="todoInput" placeholder="משימה חדשה...">
        <button type="submit">הוסף</button>
    </form>
    <ul id="todoList"></ul>
</div>

JavaScript

const form = document.querySelector("#todoForm");
const input = document.querySelector("#todoInput");
const list = document.querySelector("#todoList");

// הוספת משימה
form.addEventListener("submit", (e) => {
    e.preventDefault();

    const text = input.value.trim();
    if (!text) return;

    const li = document.createElement("li");
    li.innerHTML = `
        <span>${text}</span>
        <button class="delete">מחק</button>
    `;

    list.appendChild(li);
    input.value = "";
    input.focus();
});

// מחיקה והשלמה (delegation)
list.addEventListener("click", (e) => {
    const li = e.target.closest("li");

    if (e.target.classList.contains("delete")) {
        li.remove();
    } else if (e.target.tagName === "SPAN") {
        li.classList.toggle("completed");
    }
});

סיכום

אירוע מתי קורה
click לחיצת עכבר
dblclick לחיצה כפולה
keydown מקש נלחץ
keyup מקש שוחרר
submit טופס נשלח
input ערך השתנה
focus אלמנט קיבל פוקוס
blur אלמנט איבד פוקוס
mouseenter עכבר נכנס
mouseleave עכבר יצא
load הדף נטען
scroll גלילה

כללי אצבע: - השתמשו ב-addEventListener - השתמשו ב-Event Delegation לביצועים טובים - השתמשו ב-preventDefault() לשלוט בהתנהגות - זכרו שאירועים "מבעבעים" למעלה

בדקו את עצמכם

נסו לענות לבד לפני שאתם פותחים את התשובה.

  1. מה עושה event.preventDefault() בשליחת טופס?

    1. מוחק את הטופס
    2. מונע את ההתנהגות הרגילה, כאן טעינה מחדש של הדף
    3. שולח פעמיים
    4. עוצר את כל ה-JavaScript
    הצגת התשובה

    תשובה ב. כך מטפלים בשליחה ב-JavaScript במקום שהדפדפן יעבור דף.

  2. מה זה event delegation?

    1. העברת אירוע לשרת
    2. אירוע שקורה פעמיים
    3. מאזין אחד על ההורה שמטפל באירועים של כל הילדים
    4. מחיקת מאזינים
    הצגת התשובה

    תשובה ג. האירוע "מבעבע" למעלה, ובודקים event.target. יעיל, ועובד גם לאלמנטים שנוספו אחר כך.