3.8 פרויקטים פרויקט
פרויקט 1 - רשימת משימות - Todo List¶
בנו אפליקציית רשימת משימות מלאה עם ממשק מעוצב ושמירה מקומית.
דרישות פונקציונליות¶
- הוספת משימה - שדה input וכפתור "add". לחיצה על הכפתור או Enter מוסיפה משימה חדשה לרשימה.
- סימון כהושלם - לחיצה על משימה מסמנת אותה כהושלמה (קו חוצה וצבע מעומעם). לחיצה נוספת מבטלת את הסימון.
- מחיקת משימה - כל משימה מכילה כפתור X למחיקה. לחיצה מסירה את המשימה מהרשימה.
- סינון - שלושה כפתורי סינון:
- "all" - מציג את כל המשימות
- "active" - מציג רק משימות שלא הושלמו
- "completed" - מציג רק משימות שהושלמו
- מונה משימות - הציגו "X tasks remaining" שמתעדכן בזמן אמת (סופר רק משימות פעילות).
- שמירה ל-localStorage - כל שינוי (הוספה, מחיקה, סימון) נשמר אוטומטית. כשטוענים את הדף מחדש, הרשימה משוחזרת.
- אנימציות - כשמוסיפים משימה, היא נכנסת עם אנימציה (slide in או fade in). כשמוחקים, היא יוצאת עם אנימציה (fade out) ורק אז מוסרת מה-DOM.
דרישות טכניות¶
- השתמשו בדלגציית אירועים - handler אחד על ה-ul לכל הלחיצות על משימות
- כל משימה נשמרת כאובייקט עם id, text, ו-completed
- השתמשו ב-
JSON.stringifyו-JSON.parseלשמירה וטעינה מ-localStorage - ה-id של כל משימה יכול להיות
Date.now()ברגע היצירה
דרישות עיצוב¶
- עיצוב נקי ומודרני
- רקע בהיר, כרטיס לבן עם צל
- שדה ה-input בולט עם מסגרת
- כפתור ההוספה בצבע בולט
- משימות שהושלמו עם קו חוצה וטקסט אפור
- כפתורי הסינון - הכפתור הפעיל מודגש
- כפתור המחיקה מופיע רק ב-hover על המשימה
מבנה HTML מוצע¶
<div class="todo-app">
<h1>todo list</h1>
<div class="input-section">
<input type="text" id="todo-input" placeholder="what needs to be done?">
<button id="add-btn">add</button>
</div>
<div class="filters">
<button class="filter-btn active" data-filter="all">all</button>
<button class="filter-btn" data-filter="active">active</button>
<button class="filter-btn" data-filter="completed">completed</button>
</div>
<ul id="todo-list"></ul>
<p id="task-count"></p>
</div>
טיפים¶
- שמרו מערך של אובייקטי משימות:
[{ id: 123, text: "...", completed: false }, ...] - בכל שינוי, שמרו את כל המערך ל-localStorage ורנדרו מחדש
- לאנימציות, הוסיפו class ותנו ל-CSS transition לעשות את העבודה. למחיקה, הוסיפו class של "removing", חכו שהאנימציה תסתיים (setTimeout), ואז הסירו מה-DOM
- לסינון, אל תמחקו אלמנטים - פשוט הסתירו/הציגו עם display
פרויקט 2 - מחשבון ויזואלי - Visual Calculator¶
בנו מחשבון עם ממשק גרפי שעובד עם עכבר ומקלדת.
דרישות פונקציונליות¶
- כפתורים - כפתורים לספרות 0-9, פעולות (+, -, *, /), נקודה עשרונית, שווה (=), ניקוי (C), מחיקת תו אחרון (backspace).
- תצוגה - אזור תצוגה שמראה את הקלט הנוכחי ואת התוצאה. הציגו גם את הפעולה הנוכחית (למשל "5 + 3").
- חישוב - לחיצה על = מחשבת את התוצאה ומציגה אותה. התוצאה הופכת לקלט הבא (אפשר להמשיך לחשב).
- שרשור פעולות - תמיכה בחישוב רציף. למשל: 3 + 5 = 8, ואז * 2 = 16.
- תמיכת מקלדת - לחיצה על מקשים מפעילה את הכפתורים המתאימים:
- מקשי 0-9 ונקודה עשרונית
- מקשי +, -, *, /
- Enter = חישוב
- Escape = ניקוי
- Backspace = מחיקת תו אחרון
- היסטוריה - רשימה מתחת למחשבון שמציגה את החישובים האחרונים (למשל "5 + 3 = 8"). ההיסטוריה נשמרת ב-localStorage.
דרישות טכניות¶
- השתמשו בדלגציית אירועים - handler אחד על ה-div של הכפתורים
- כל כפתור עם
data-valueattribute שמציין את הערך שלו - אירוע keydown על document לתמיכת מקלדת
- היסטוריה נשמרת כמערך ב-localStorage
דרישות עיצוב¶
- layout של הכפתורים ב-CSS Grid (4 עמודות, כמו מחשבון אמיתי)
- כפתור = תופס 2 שורות או 2 עמודות
- כפתור 0 תופס 2 עמודות
- צבעים שונים לכפתורי ספרות, פעולות, וניקוי
- אזור תצוגה גדול עם טקסט מיושר לימין
- אפקט hover ו-active (לחיצה) על כל כפתור
- כשלוחצים מקש במקלדת, הכפתור המתאים מקבל הדגשה ויזואלית לרגע
מבנה HTML מוצע¶
<div class="calculator">
<div class="display">
<div class="display-expression">5 + 3</div>
<div class="display-result">8</div>
</div>
<div class="buttons">
<button data-value="C" class="btn-clear">C</button>
<button data-value="backspace" class="btn-clear">DEL</button>
<button data-value="/" class="btn-operator">/</button>
<button data-value="*" class="btn-operator">*</button>
<button data-value="7">7</button>
<button data-value="8">8</button>
<button data-value="9">9</button>
<button data-value="-" class="btn-operator">-</button>
<button data-value="4">4</button>
<button data-value="5">5</button>
<button data-value="6">6</button>
<button data-value="+" class="btn-operator">+</button>
<button data-value="1">1</button>
<button data-value="2">2</button>
<button data-value="3">3</button>
<button data-value="=" class="btn-equals">=</button>
<button data-value="0" class="btn-zero">0</button>
<button data-value=".">.</button>
</div>
</div>
<div class="history">
<h3>history</h3>
<ul id="calc-history"></ul>
<button id="clear-history">clear history</button>
</div>
טיפים¶
- שמרו את מצב המחשבון במשתנים: currentNumber, previousNumber, operator
- כשלוחצים ספרה, הוסיפו אותה ל-currentNumber (כמחרוזת, ואז המירו למספר בחישוב)
- כשלוחצים operator, שמרו את currentNumber ב-previousNumber ואפסו את currentNumber
- כשלוחצים =, חשבו את התוצאה מ-previousNumber operator currentNumber
- היזהרו מחילוק באפס - הציגו הודעת שגיאה
- היזהרו מנקודות עשרוניות כפולות
פרויקט 3 - משחק חידון - Quiz App¶
בנו אפליקציית חידון עם שאלות רב-ברירה, טיימר, וציונים.
דרישות פונקציונליות¶
- מאגר שאלות - מערך של לפחות 10 שאלות. כל שאלה מכילה: טקסט השאלה, מערך של 4 תשובות אפשריות, אינדקס התשובה הנכונה.
- הצגת שאלה - הציגו שאלה אחת בכל פעם עם 4 כפתורי תשובה.
- טיימר - כל שאלה מקבלת 15 שניות. הטיימר מוצג ויזואלית (פס שהולך ונגמר, או מספר שיורד). אם הזמן נגמר, השאלה נספרת כשגויה ועוברים לשאלה הבאה.
- משוב מיידי - כשבוחרים תשובה:
- תשובה נכונה - הכפתור הופך ירוק
- תשובה שגויה - הכפתור שנבחר הופך אדום, והתשובה הנכונה הופכת ירוקה
- חכו 1-2 שניות ואז עברו לשאלה הבאה
- מעקב ציון - הציגו ציון נוכחי (כמה נכונות מתוך כמה נענו) וסרגל התקדמות.
- מסך תוצאות - בסוף כל השאלות הציגו:
- ציון סופי (X/10)
- אחוז הצלחה
- פירוט - רשימת כל השאלות עם סימון נכון/שגוי
- הצגת התשובה הנכונה לכל שאלה שנענתה לא נכון
- התחלה מחדש - כפתור "play again" שמערבב את השאלות ומתחיל מחדש.
- ציון גבוה - שמרו את הציון הגבוה ביותר ב-localStorage. הציגו אותו במסך הפתיחה.
דרישות טכניות¶
- השתמשו בדלגציית אירועים לכפתורי התשובות
setTimeoutלמעבר בין שאלותsetIntervalלטיימר (אל תשכחו לעצור אותו ב-clearInterval)Math.randomו-sortלערבוב שאלות וסדר תשובות
דרישות עיצוב¶
- מסך פתיחה עם שם המשחק, הציון הגבוה, וכפתור "start"
- כרטיס שאלה במרכז המסך
- כפתורי תשובה גדולים ונוחים ללחיצה
- פס טיימר שמשנה צבע (ירוק -> כתום -> אדום) ככל שהזמן אוזל
- סרגל התקדמות "question X of 10"
- מסך תוצאות עם עיצוב ברור - ירוק לנכון, אדום לשגוי
מבנה נתונים מוצע¶
let questions = [
{
question: "What does HTML stand for?",
answers: [
"Hyper Text Markup Language",
"High Tech Modern Language",
"Hyper Transfer Markup Language",
"Home Tool Markup Language"
],
correct: 0
},
{
question: "Which CSS property changes the text color?",
answers: [
"text-color",
"font-color",
"color",
"text-style"
],
correct: 2
}
// ... more questions
];
טיפים¶
- חלקו את הקוד לפונקציות ברורות: showQuestion, checkAnswer, nextQuestion, showResults, startGame
- שמרו את מצב המשחק במשתנים: currentQuestionIndex, score, answers (מערך של תשובות המשתמש)
- לטיימר, השתמשו ב-setInterval שרץ כל שניה ומעדכן את התצוגה. עצרו אותו עם clearInterval כשבוחרים תשובה
- לערבוב, השתמשו באלגוריתם Fisher-Yates shuffle
פרויקט 4 - משחק זיכרון - Memory Game¶
בנו משחק זיכרון קלאסי - מצאו זוגות תואמים של קלפים.
דרישות פונקציונליות¶
- לוח משחק - רשת של קלפים (4x4 = 16 קלפים = 8 זוגות). כל הקלפים מתחילים הפוכים (מוסתרים).
- חשיפת קלפים - לחיצה על קלף חושפת אותו (אנימציית הפיכה). אפשר לחשוף שני קלפים בכל תור.
- בדיקת התאמה:
- אם שני הקלפים שנחשפו תואמים - הם נשארים גלויים
- אם הם לא תואמים - חכו 1 שניה ואז הפכו אותם חזרה
- תוכן הקלפים - השתמשו בסמלים או אימוג'ים (אפשר גם טקסט פשוט כמו A, B, C...). כל סמל מופיע בדיוק פעמיים.
- מונה מהלכים - ספרו כמה מהלכים (זוגות לחיצות) המשתמש ביצע.
- טיימר - הציגו את הזמן שעובר מתחילת המשחק (דקות:שניות).
- תנאי ניצחון - כשכל הזוגות נמצאו:
- הציגו הודעת ניצחון
- הציגו את מספר המהלכים והזמן
- השוו לציון הטוב ביותר (נשמר ב-localStorage)
- כפתור "play again" להתחלה מחדש
- ערבוב - בכל משחק חדש, הקלפים מעורבבים באקראי.
דרישות טכניות¶
- השתמשו בדלגציית אירועים - handler אחד על הלוח כולו
- אנימציית הפיכת קלף עם CSS transform (
rotateY(180deg)) ו-transition setIntervalלטיימר- שמרו את הציון הטוב ביותר ב-localStorage (מספר מהלכים מינימלי, או זמן מינימלי)
דרישות עיצוב¶
- רשת הקלפים ב-CSS Grid (4 עמודות)
- כל קלף הוא ריבוע עם פינות מעוגלות
- צד אחורי של הקלף בצבע אחיד עם סימן שאלה או דפוס
- צד קדמי מציג את הסמל בגדול ובצבע
- אנימציית הפיכה תלת-ממדית (perspective + rotateY)
- קלפים שנמצא להם זוג מקבלים אפקט ויזואלי (צבע רקע שונה, או גבול ירוק)
- פס מידע עליון עם מהלכים, טיימר, וכפתור restart
- מסך ניצחון עם אנימציה
מבנה HTML מוצע¶
<div class="memory-game">
<div class="game-info">
<span>moves: <span id="moves-count">0</span></span>
<span>time: <span id="timer">00:00</span></span>
<span>best: <span id="best-score">-</span></span>
<button id="restart-btn">restart</button>
</div>
<div class="game-board" id="game-board">
<!-- cards will be generated by JavaScript -->
</div>
</div>
<!-- victory modal -->
<div id="victory-modal" style="display: none;">
<div class="modal-content">
<h2>you won!</h2>
<p>moves: <span id="final-moves"></span></p>
<p>time: <span id="final-time"></span></p>
<p id="new-record" style="display: none;">new record!</p>
<button id="play-again">play again</button>
</div>
</div>
מבנה CSS לאנימציית הפיכה¶
.card {
perspective: 1000px;
cursor: pointer;
aspect-ratio: 1;
}
.card-inner {
width: 100%;
height: 100%;
position: relative;
transition: transform 0.5s;
transform-style: preserve-3d;
}
.card.flipped .card-inner {
transform: rotateY(180deg);
}
.card-front, .card-back {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
}
.card-back {
background: #3498db;
color: white;
font-size: 2rem;
}
.card-front {
background: white;
transform: rotateY(180deg);
font-size: 2.5rem;
}
טיפים¶
- צרו מערך של סמלים, שכפלו אותו (כדי שכל סמל יהיה פעמיים), ועירבבו
- שמרו שני משתנים: firstCard ו-secondCard. כשלוחצים קלף ראשון, שמרו אותו. כשלוחצים שני, השוו
- בזמן שמחכים שהקלפים ייהפכו בחזרה (1 שניה), חסמו לחיצות נוספות (דגל isChecking)
- אל תאפשרו לחיצה על קלף שכבר גלוי או שכבר נמצא לו זוג
- לערבוב Fisher-Yates:
function shuffle(array) {
for (let i = array.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1));
let temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
- לטיימר, שמרו את זמן ההתחלה (
Date.now()) וחשבו את ההפרש בכל שניה - הציון הטוב ביותר יכול להיות מבוסס על מספר מהלכים בלבד (פשוט יותר) או על שילוב של מהלכים וזמן