Мини-проект — Интерактивный список дел
Короткий список на этой странице вы собираете сами. Пока дело открыто, строка показывает buy tea. Когда оно отмечено, строка показывает done: buy tea. Путь такой: добавить buy tea, отметить готовым, затем убрать.
Прошлая страница назвала умения и замолчала
Списка там не было. Эта страница и есть список. Вам нужны массив, форма, textContent и щелчок. Добавление не должно перезагружать страницу.
В tasks лежат объекты
У каждого объекта есть text и done. Новый элемент начинает с done, равного false. addTask прогоняет слова через trim. Если ничего не осталось, push не вызывается и элемент не сохраняется.
const tasks = [];
function addTask(text) {
const clean = text.trim();
if (!clean) {
return;
}
tasks.push({ text: clean, done: false });
}
addTask("buy tea");
console.log(tasks[0].text);
console.log(tasks[0].done);
Два журнала идут так: buy tea, затем false. addTask(" ") после trim пуст, ничего не сохраняет, длина остаётся 0.
Перезагрузка роняет память
Отправка формы перезагружает документ. Массив живёт только в памяти, поэтому перезагрузка его роняет и список выглядит пустым. event.preventDefault() останавливает эту перезагрузку. Потом вы берёте текст, очищаете поле и рисуете снова.
const form = document.querySelector("#add-form");
const input = document.querySelector("#task-text");
form.addEventListener("submit", (event) => {
event.preventDefault();
addTask(input.value);
input.value = "";
render();
});
Документ остаётся. Поле пустое. render выполняется. Поле из одних пробелов не добавляет строку.
Две кнопки, которые не отправляют форму
render очищает #tasks и строит по одному li на элемент. Открытый показывает text. Готовый показывает done: и следом текст. В каждой строке две кнопки, обе с type="button", чтобы щелчок не отправлял форму. Done переворачивает логическое значение. Удаление идёт через splice. Оба потом рисуют снова: старые индексы указывали бы не на тот элемент.
function toggleTask(index) {
tasks[index].done = !tasks[index].done;
}
function removeTask(index) {
tasks.splice(index, 1);
}
function render() {
const list = document.querySelector("#tasks");
list.textContent = "";
tasks.forEach((task, index) => {
const item = document.createElement("li");
item.textContent = task.done ? "done: " + task.text : task.text;
const doneButton = document.createElement("button");
doneButton.type = "button";
doneButton.textContent = "Done";
doneButton.addEventListener("click", () => {
toggleTask(index);
render();
});
const removeButton = document.createElement("button");
removeButton.type = "button";
removeButton.textContent = "Remove";
removeButton.addEventListener("click", () => {
removeTask(index);
render();
});
item.append(doneButton, removeButton);
list.append(item);
});
}
Порядок: addTask("buy tea"), toggleTask(0), render. Строка становится done: buy tea. Ещё одно переключение возвращает buy tea. removeTask(0) делает длину 0, и следующий рисунок без строк. Слова поля кладите через textContent. Не вставляйте их на страницу как HTML.
Индекс принадлежит этому проходу
forEach захватывает индекс именно этого прохода. После splice старые номера указывают не на ту задачу. Новый рисунок выбрасывает старые кнопки и делает новые. Без этого второго рисунка Remove удаляет не ту строку.
Три роли
Форма добавляет. Список рисует. Done и Remove меняют только tasks, затем рисуют снова.
<!DOCTYPE html>
<html>
<body>
<form id="add-form">
<input id="task-text" type="text">
<button type="submit">Add</button>
</form>
<ul id="tasks"></ul>
<script>
const tasks = [];
function addTask(text) {
const clean = text.trim();
if (!clean) return;
tasks.push({ text: clean, done: false });
}
function toggleTask(index) {
tasks[index].done = !tasks[index].done;
}
function removeTask(index) {
tasks.splice(index, 1);
}
function render() {
const list = document.querySelector("#tasks");
list.textContent = "";
tasks.forEach((task, index) => {
const item = document.createElement("li");
item.textContent = task.done ? "done: " + task.text : task.text;
const doneButton = document.createElement("button");
doneButton.type = "button";
doneButton.textContent = "Done";
doneButton.addEventListener("click", () => {
toggleTask(index);
render();
});
const removeButton = document.createElement("button");
removeButton.type = "button";
removeButton.textContent = "Remove";
removeButton.addEventListener("click", () => {
removeTask(index);
render();
});
item.append(doneButton, removeButton);
list.append(item);
});
}
document.querySelector("#add-form").addEventListener("submit", (event) => {
event.preventDefault();
addTask(document.querySelector("#task-text").value);
document.querySelector("#task-text").value = "";
render();
});
</script>
</body>
</html>
Введите buy tea и нажмите Add. Строка — buy tea, поле очищается. Нажмите Done — строка done: buy tea. Нажмите Remove — список пуст. Add на пустом поле ничего не добавляет.
Пять шагов за столом
- Вызовите addTask("buy tea"). Первый text — buy tea, done равен false.
- Отправьте форму. Страница не перезагружается, строка появляется.
- Нажмите Done. Строка показывает done: buy tea.
- Нажмите Remove. tasks.length равен 0.
- Отправьте одни пробелы. Список не растёт.
Настоящие промахи
- пропустить preventDefault, и массив гибнет при отправке
- сделать push пустой строки
- поставить type="submit" на Done или Remove
- стереть строку на экране и забыть splice, так что следующий рисунок вернёт её
- пропустить render после splice
- записать поле на страницу как HTML
Что унести с собой
- Задача — это { text, done }, и done начинается с false
- addTask("buy tea") сохраняет buy tea, пустое поле не сохраняет ничего
- preventDefault держит страницу, render рисует строки
- Done показывает done: buy tea, Remove оставляет длину 0
- Рисуйте снова после каждого изменения
🧠 Проверьте Свои Знания
Проверьте Свои Знания
Бросьте себе вызов с помощью этой интерактивной викторины и узнайте, насколько хорошо вы понимаете тему
📝 Инструкции
- Внимательно прочитайте каждый вопрос
- Выберите лучший ответ на каждый вопрос
- Вы можете пересдавать тест столько раз, сколько захотите
- Ваш прогресс будет показан вверху