Создание интерактивного списка задач (todo list)

Тренажер по работе с HTML DOM на JavaScript для пользователей с начальным и средним уровнем подготовки.

Тренажер JavaScript: Покоряем HTML DOM

Этот набор заданий поможет вам попрактиковаться в манипулировании HTML DOM с помощью JavaScript для создания классического приложения - списка задач (Todo List). Вы начнете с основ: выбора элементов и добавления новых задач. Затем перейдете к более сложным вещам, таким как отметка задач как выполненных и их удаление. Каждое задание предоставляет готовый HTML и частично написанный JavaScript код, который вам нужно будет дополнить, чтобы реализовать требуемую функциональность. Это отличный способ закрепить знания по работе с событиями, созданию и изменению элементов DOM.

Список тем

Выбор элементов для Todo List

Для начала работы с нашим списком задач нам нужно получить доступ к основным элементам на странице: полю для ввода новой задачи, кнопке для добавления задачи и списку, куда будут добавляться задачи. Ваша задача - используя JavaScript, найти эти три элемента по их ID и сохранить их в переменные.

HTML
Восстановить HTML
<input type="text" id="taskInput" placeholder="Новая задача...">
<button id="addButton">Добавить</button>
<ul id="taskList"></ul>
JavaScript
const taskInput = document.input__1("taskInput");
const addButton = document.getElementById(input__2);
const taskList = input__3.getElementById("taskList");

// Для проверки можешь вывести элементы в консоль (не обязательно)
console.log(taskInput, addButton, taskList);
Используйте метод `document.getElementById()` для поиска элемента по его уникальному идентификатору (атрибуту `id`). Передайте ID нужного элемента в качестве строки этому методу.
Заполнить ответами все поля
Результат
Лог
Выполнить
Отметить решенным
Показать подсказку

Добавление новой задачи в список

Теперь реализуем основную функцию: добавление новой задачи. При нажатии на кнопку 'Добавить' должен создаваться новый элемент списка (`<li>`), текст для него браться из поля ввода, и этот новый элемент должен добавляться в конец списка `<ul>`.

HTML
Восстановить HTML
<input type="text" id="taskInput" placeholder="Новая задача...">
<button id="addButton">Добавить</button>
<ul id="taskList"></ul>
JavaScript
const taskInput = document.getElementById("taskInput");
const addButton = document.getElementById("addButton");
const taskList = document.getElementById("taskList");

addButton.input__1("click", function() {
  const taskText = taskInput.input__2;

  // Создаем новый элемент списка
  const newTask = document.input__3("li");

  // Устанавливаем текст задачи
  newTask.input__4 = taskText;

  // Добавляем задачу в список
  taskList.input__5(newTask);

  // Очищаем поле ввода (добавим в следующем шаге)
  // taskInput.value = "";
});
Добавьте обработчик события 'click' на кнопку. Внутри обработчика получите значение поля ввода (`.value`). Создайте новый элемент `<li>` с помощью `document.createElement()`. Установите его текстовое содержимое (`.textContent`). Добавьте созданный элемент в `taskList` с помощью метода `.appendChild()`.
Заполнить ответами все поля
Результат
Лог
Выполнить
Отметить решенным
Показать подсказку

Очистка поля ввода и проверка на пустую задачу

Улучшим предыдущий шаг. Во-первых, после добавления задачи поле ввода должно автоматически очищаться. Во-вторых, не нужно добавлять пустые задачи. Добавьте проверку: если поле ввода пустое (или содержит только пробелы), задача не должна добавляться.

HTML
Восстановить HTML
<input type="text" id="taskInput" placeholder="Новая задача...">
<button id="addButton">Добавить</button>
<ul id="taskList"></ul>
JavaScript
const taskInput = document.getElementById("taskInput");
const addButton = document.getElementById("addButton");
const taskList = document.getElementById("taskList");

addButton.addEventListener("click", function() {
  const taskText = taskInput.value.input__1(); // Удаляем пробелы по краям

  // Проверяем, не пустая ли строка
  if (taskText input__2 "") {
    const newTask = document.createElement("li");
    newTask.textContent = taskText;
    taskList.appendChild(newTask);

    // Очищаем поле ввода
    taskInput.input__3 = input__4;
  }
});
Чтобы очистить поле ввода, установите его свойство `.value` в пустую строку (`''`). Для проверки на пустоту используйте условный оператор `if`. Получите значение поля ввода, удалите пробелы по краям с помощью метода `.trim()` и сравните результат с пустой строкой. Весь код создания и добавления `<li>` должен находиться внутри блока `if`.
Заполнить ответами все поля
Результат
Лог
Выполнить
Отметить решенным
Показать подсказку

Отметка задачи как выполненной

Добавим интерактивности: при клике на любую задачу в списке она должна помечаться как выполненная (или наоборот, если уже была выполнена). Визуально это будет достигаться добавлением/удалением CSS-класса `completed`, который перечеркивает текст.

CSS
ul {
  list-style: none;
  padding: 0;
}
li {
  padding: 8px;
  border-bottom: 1px solid #eee;
  cursor: pointer;
}
li:hover {
  background-color: #f9f9f9;
}
.completed {
  text-decoration: line-through;
  color: #aaa;
}
HTML
Восстановить HTML
<input type="text" id="taskInput" placeholder="Новая задача...">
<button id="addButton">Добавить</button>
<ul id="taskList">
  <li>Пример задачи 1</li>
  <li>Пример задачи 2</li>
</ul>
JavaScript
const taskInput = document.getElementById("taskInput");
const addButton = document.getElementById("addButton");
const taskList = document.getElementById("taskList");

// Код добавления задачи (из предыдущего шага)
addButton.addEventListener("click", function() {
  const taskText = taskInput.value.trim();
  if (taskText !== "") {
    const newTask = document.createElement("li");
    newTask.textContent = taskText;
    taskList.appendChild(newTask);
    taskInput.value = "";
  }
});

// Обработчик для отметки выполнения
taskList.addEventListener(input__1, function(input__2) {
  // Проверяем, что клик был по элементу LI
  if (event.input__3.tagName === input__4) {
    // Переключаем класс 'completed'
    event.target.input__5.toggle("completed");
  }
});
Используйте делегирование событий. Добавьте один обработчик события 'click' на весь список `taskList`. Внутри обработчика проверьте, был ли клик сделан именно по элементу `<li>` (можно проверить `event.target.tagName`). Если да, то используйте `event.target.classList.toggle()` для добавления/удаления класса `completed`.
Заполнить ответами все поля
Результат
Лог
Выполнить
Отметить решенным
Показать подсказку

Добавление кнопки удаления для каждой задачи

Каждая задача должна иметь кнопку для ее удаления. Измените код добавления новой задачи так, чтобы вместе с текстом задачи в `<li>` добавлялся элемент (например, `<span>` или `<button>`) с текстом 'X' или символом ×, который будет служить кнопкой удаления. Добавьте этой кнопке CSS-класс `delete-btn` для стилизации и дальнейшего использования.

CSS
ul {
  list-style: none;
  padding: 0;
}
li {
  padding: 8px;
  border-bottom: 1px solid #eee;
  display: flex; /* Для расположения текста и кнопки в строку */
  justify-content: space-between; /* Разнести текст и кнопку по краям */
  align-items: center;
}
.completed {
  text-decoration: line-through;
  color: #aaa;
}
.delete-btn {
  color: red;
  cursor: pointer;
  margin-left: 10px; /* Небольшой отступ слева */
  font-weight: bold;
}
.delete-btn:hover {
  color: darkred;
}
HTML
Восстановить HTML
<input type="text" id="taskInput" placeholder="Новая задача...">
<button id="addButton">Добавить</button>
<ul id="taskList"></ul>
JavaScript
const taskInput = document.getElementById("taskInput");
const addButton = document.getElementById("addButton");
const taskList = document.getElementById("taskList");

addButton.addEventListener("click", function() {
  const taskText = taskInput.value.trim();
  if (taskText !== "") {
    const newTask = document.createElement("li");
    newTask.textContent = taskText; // Устанавливаем основной текст задачи

    // Создаем кнопку удаления
    const deleteBtn = document.input__1("span"); 
    deleteBtn.textContent = input__2; // Текст кнопки
    deleteBtn.input__3.add(input__4); // Добавляем класс

    // Добавляем кнопку внутрь li
    newTask.input__5(deleteBtn);

    taskList.appendChild(newTask);
    taskInput.value = "";
  }
});

// Обработчик для отметки выполнения (оставляем из предыдущего шага)
taskList.addEventListener("click", function(event) {
  // Пока обрабатываем только клик по LI для выполнения
  if (event.target.tagName === "LI") {
     // Проверяем, чтобы клик не был по кнопке удаления внутри LI
     if (!event.target.querySelector('.delete-btn') || !event.target.querySelector('.delete-btn').contains(event.target)) {
        event.target.classList.toggle("completed");
     }
  }
});
Внутри обработчика добавления задачи, после создания `<li>` и установки `textContent`, создайте еще один элемент (например, `<span>`) с помощью `document.createElement()`. Установите его `textContent` в ' × ' (или 'X'). Добавьте ему класс `delete-btn` с помощью `classList.add()`. Затем добавьте этот `<span>` внутрь `<li>` с помощью `newTask.appendChild()`.
Заполнить ответами все поля
Результат
Лог
Выполнить
Отметить решенным
Показать подсказку

Реализация удаления задачи

Завершающий шаг: сделаем кнопку удаления рабочей. Используя делегирование событий на списке `taskList`, определите, был ли клик по элементу с классом `delete-btn`. Если да, то нужно найти родительский элемент `<li>` этой кнопки и удалить его из DOM.

CSS
ul {
  list-style: none;
  padding: 0;
}
li {
  padding: 8px;
  border-bottom: 1px solid #eee;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
li span:first-child {
    cursor: pointer; /* Делаем текст задачи кликабельным для выполнения */
    flex-grow: 1; /* Позволяем тексту занимать доступное место */
    margin-right: 10px;
}
.completed span:first-child {
  text-decoration: line-through;
  color: #aaa;
}
.delete-btn {
  color: red;
  cursor: pointer;
  font-weight: bold;
  padding: 0 5px; /* Небольшие отступы для кнопки */
}
.delete-btn:hover {
  color: darkred;
}
HTML
Восстановить HTML
<!-- Изменим структуру LI, чтобы текст был в отдельном span для корректной работы клика --> 
<input type="text" id="taskInput" placeholder="Новая задача...">
<button id="addButton">Добавить</button>
<ul id="taskList">
  <li><span>Пример задачи 1</span><span class="delete-btn">×</span></li>
  <li><span>Пример задачи 2</span><span class="delete-btn">×</span></li>
</ul>
JavaScript
const taskInput = document.getElementById("taskInput");
const addButton = document.getElementById("addButton");
const taskList = document.getElementById("taskList");

// Код добавления задачи с кнопкой удаления
addButton.addEventListener("click", function() {
  const taskText = taskInput.value.trim();
  if (taskText !== "") {
    const newTask = document.createElement("li");
    
    // Создаем span для текста задачи
    const taskTextSpan = document.createElement('span');
    taskTextSpan.textContent = taskText;
    newTask.appendChild(taskTextSpan);

    // Создаем кнопку удаления
    const deleteBtn = document.createElement("span"); 
    deleteBtn.textContent = " × "; 
    deleteBtn.classList.add("delete-btn");
    newTask.appendChild(deleteBtn);

    taskList.appendChild(newTask);
    taskInput.value = "";
  }
});

// Общий обработчик кликов на списке
taskList.addEventListener("click", function(event) {
  // Проверка клика по кнопке удаления
  if (event.target.input__1.input__2("delete-btn")) {
    const taskItem = event.target.input__3; // Получаем родительский LI
    taskItem.input__4(); // Удаляем LI
  }
  // Проверка клика по тексту задачи для выполнения (кликаем на SPAN внутри LI)
  else if (event.target.tagName === "SPAN" && !event.target.classList.contains("delete-btn")) {
     // Применяем класс к родительскому LI
     event.target.parentElement.classList.toggle("completed");
  }
});
Дополните существующий обработчик клика на `taskList`. Добавьте проверку: если `event.target` имеет класс `delete-btn` (используйте `event.target.classList.contains()`), то получите его родительский элемент `<li>` (с помощью `event.target.parentElement`). Затем удалите этот родительский элемент из DOM, вызвав у него метод `.remove()`.
Заполнить ответами все поля
Результат
Лог
Выполнить
Отметить решенным
Показать подсказку
НайтиКурс.Ру
Добавить комментарий