Проект: мини-сайт с JavaScript

Собираем мини-сайт с формой, списком задач и динамикой на JavaScript. Финальный урок курса для начинающих от студии IZE.

Финальный проект — мини-сайт с динамикой на JavaScript

В этом уроке мы соберём полноценную страницу, которая будет включать:

  • ToDo-лист с сохранением в localStorage,
  • Форму обратной связи,
  • Получение данных с сервера (fetch),
  • Асинхронный счётчик.

Этот мини-сайт объединяет всё, что ты изучал на курсе. Готов?

HTML + CSS разметка

<!-- Кнопки Главного меню -->
<div>
  <button class="js-menu-btn active">Главная</button>
  <button class="js-menu-btn">О нас</button>
  <button class="js-menu-btn">Контакты</button>
</div>

<style>
  .js-menu-btn {
    background: #f5f5dc;
    border: none;
    padding: 0.5em 1em;
    cursor: pointer;
    margin-right: 0.5em;
    border-radius: 5px;
    font-size: 1em;
    transition: background-color 0.3s ease;
  }
  .js-menu-btn.active {
    background: #003366;
    color: white;
  }
  .js-menu-btn:hover:not(.active) {
    background: #e0d8b0;
  }
</style>

        <div id="miniSite">
  <!-- ToDo блок -->
  <div class="block">
    <h2>Список задач</h2>
    <input id="taskInput" placeholder="Новая задача...">
    <button id="addTask">Добавить</button>
    <ul id="tasks"></ul>
  </div>

  <!-- Форма обратной связи -->
  <div class="block">
    <h2>Обратная связь</h2>
    <input id="name" placeholder="Ваше имя">
    <input id="email" placeholder="Email">
    <textarea id="message" placeholder="Сообщение" rows="3"></textarea>
    <button id="sendForm">Отправить</button>
    <p id="formStatus"></p>
  </div>

  <!-- API fetch -->
  <div class="block">
    <h2>Случайный факт о числе</h2>
    <button id="loadFact">Загрузить факт</button>
    <p id="factOutput"></p>
  </div>

  <!-- Таймер -->
  <div class="block">
    <h2>Обратный отсчёт</h2>
    <div id="countdown" style="font-size: 2em;">5</div>
    <button onclick="location.reload()"><i class="fa fa-refresh"></i></button>
  </div>
</div>

JavaScript

<script>
// ToDo
const taskInput = document.getElementById("taskInput");
const addTask = document.getElementById("addTask");
const tasks = document.getElementById("tasks");

function loadTasks() {
  const saved = localStorage.getItem("tasks");
  if (saved) tasks.innerHTML = saved;
  tasks.querySelectorAll("button").forEach(btn => {
    btn.onclick = () => { btn.parentElement.remove(); saveTasks(); };
  });
}
function saveTasks() {
  localStorage.setItem("tasks", tasks.innerHTML);
}
function createTask(text) {
  const li = document.createElement("li");
  li.className = "todo-item";
  li.innerHTML = text + ' <button>Удалить</button>';
  li.querySelector("button").onclick = () => {
    li.remove();
    saveTasks();
  };
  tasks.appendChild(li);
  saveTasks();
}
addTask.onclick = () => {
  const text = taskInput.value.trim();
  if (text) {
    createTask(text);
    taskInput.value = "";
  }
};
taskInput.addEventListener("keydown", e => {
  if (e.key === "Enter") addTask.click();
});
loadTasks();

// Форма
const sendForm = document.getElementById("sendForm");
sendForm.onclick = () => {
  const name = document.getElementById("name").value.trim();
  const email = document.getElementById("email").value.trim();
  const msg = document.getElementById("message").value.trim();
  if (!name || !email || !msg) {
    document.getElementById("formStatus").textContent = "Пожалуйста, заполните все поля.";
  } else {
    document.getElementById("formStatus").textContent = "Спасибо за сообщение, " + name + "!";
  }
};

// Fetch
document.getElementById("loadFact").onclick = async () => {
  try {
    const res = await fetch("https://numbersapi.com/random?json");
    const data = await res.json();
    document.getElementById("factOutput").textContent = data.text;
  } catch {
    document.getElementById("factOutput").textContent = "Ошибка при получении данных.";
  }
};

// Таймер
function wait(ms) {
  return new Promise(r => setTimeout(r, ms));
}
async function countdown(sec) {
  const el = document.getElementById("countdown");
  for (let i = sec; i >= 0; i--) {
    el.textContent = i;
    await wait(1000);
  }
  el.textContent = "Время вышло!";
}
countdown(5);
</script>

Попробуйте прямо здесь:

Список задач

    Обратная связь

    Получить случайного пользователя

    Таймер обратного отсчёта

    5

    Совет: Даже маленькие проекты помогут тебе стать уверенным разработчиком. Делай копии, изменяй, пробуй новые идеи и записывай, что получилось.

    Что дальше

    Ты прошёл весь курс — это уже большое достижение. Но это только начало.

    • Продолжай изучать JavaScript: разберись с модулями, классами, анимацией.
    • Начни изучать фреймворки: React, Vue или Svelte.
    • Создай свой сайт-портфолио, покажи проекты миру.

    Разработка — это путь постоянного роста. Учись, ошибайся, улучшайся.