Гид по технологиям

Как создать приложение To‑Do с CRUD на JavaScript и работе с DOM

5 min read JavaScript Обновлено 19 Dec 2025
To‑Do с CRUD на JavaScript и DOM
To‑Do с CRUD на JavaScript и DOM

Иллюстрация: макет приложения To‑Do

Введение

Document Object Model (DOM) — это представление структуры и содержимого веб‑страницы в виде объектов. С помощью JavaScript вы можете получить доступ ко всем элементам DOM и динамически создавать, читать, изменять и удалять их (CRUD).

Эта статья пошагово объясняет, как выполнять CRUD‑операции на примере списка задач. Предполагается, что вы знакомы с основами HTML и JavaScript.

Краткая идея DOM‑манипуляций

Работа с DOM обычно идёт по схеме: найти элемент, подписаться на события, в обработчике менять состояние приложения и отображение. Пример для кнопки:


В этом примере переменная submitButton ссылается на HTML‑элемент кнопки. При клике срабатывает обработчик и появляется всплывающее окно.

Макет страницы: HTML и TailwindCSS

Ниже — минимальная верстка приложения. Элементы имеют id, чтобы к ним можно было обращаться из JavaScript. Для стилизации используется TailwindCSS через CDN; можно заменить на любой CSS‑фреймворк.



To-Do List App

Так выглядит интерфейс после первичной стилизации:

Интерфейс приложения To‑Do в процессе разработки

Получение элементов и начальное состояние

Первый шаг в JavaScript — получить ссылки на HTML‑элементы и инициализировать массив задач.

const text = document.getElementById("text");
const addTaskButton = document.getElementById("add-task-btn");
const saveTaskButton = document.getElementById("save-todo-btn");
const listBox = document.getElementById("listBox");
const saveInd = document.getElementById("saveIndex");

let todoArray = [];

Массив todoArray хранит задачи в памяти. Для сохранения между загрузками используется localStorage.

Добавление задач

При клике на кнопку «Add» задача добавляется в массив и записывается в localStorage. Затем обновляется отображение.

addTaskButton.addEventListener("click", (e) => {
  e.preventDefault();
  let todo = localStorage.getItem("todo");
  if (todo === null) {
    todoArray = [];
  } else {
    todoArray = JSON.parse(todo);
  }
  if (text.value.trim() === "") return; // игнорируем пустые строки
  todoArray.push(text.value.trim());
  text.value = "";
  localStorage.setItem("todo", JSON.stringify(todoArray));
  displayTodo();
});

Важно: записывать todoArray в localStorage нужно при каждой модификации — добавлении, удалении или редактировании.

Отображение списка задач

Функция displayTodo читает массив из localStorage и формирует HTML‑код для listBox, добавляя для каждой задачи кнопки редактирования и удаления.

function displayTodo() {
  let todo = localStorage.getItem("todo");
  if (todo === null) {
    todoArray = [];
  } else {
    todoArray = JSON.parse(todo);
  }
  let htmlCode = "";
  todoArray.forEach((list, ind) => {
    htmlCode += `

${list}

`; }); listBox.innerHTML = htmlCode; } // Вызов при загрузке страницы window.onload = displayTodo;

Удаление задач

Кнопка Delete вызывает функцию deleteTodo с индексом задачи. Внутри используется splice для удаления и синхронизация с localStorage.

function deleteTodo(ind) {
  let todo = localStorage.getItem("todo");
  if (todo === null) return;
  todoArray = JSON.parse(todo);
  todoArray.splice(ind, 1);
  localStorage.setItem("todo", JSON.stringify(todoArray));
  displayTodo();
}

Элементы списка задач

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

Редактирование задач

Кнопка Edit вызывает функцию edit, которая заполняет поле ввода текстом выбранной задачи, прячет кнопку добавления и показывает кнопку сохранения.

function edit(ind) {
  saveInd.value = ind;
  let todo = localStorage.getItem("todo");
  if (todo === null) return;
  todoArray = JSON.parse(todo);
  text.value = todoArray[ind];
  addTaskButton.style.display = "none";
  saveTaskButton.style.display = "block";
}

saveTaskButton.addEventListener("click", () => {
  let todo = localStorage.getItem("todo");
  if (todo === null) return;
  todoArray = JSON.parse(todo);
  let id = saveInd.value;
  if (id === "") return;
  todoArray[id] = text.value.trim();
  addTaskButton.style.display = "block";
  saveTaskButton.style.display = "none";
  text.value = "";
  localStorage.setItem("todo", JSON.stringify(todoArray));
  displayTodo();
});

Редактирование задачи в приложении To‑Do

Проверка задачи как выполненной (варианты)

Базовый пример не содержит отметки «выполнено», но её легко добавить: можно менять CSS‑класс элемента при клике, хранить флаг done в объекте задачи или хранить список индексов выполненных задач.

Простейшая модель хранения (модификация структуры):

  • Вместо строки в массиве хранить объект: { text: ‘задача’, done: false }
  • При клике на текст переключать done и перерисовывать список

Этот вариант расширяем и масштабируется для сортировки и фильтров.

Прогресс выполнения списка задач

Мини‑методология разработки и тестирования

  1. Начните с простого: текстовые строки и localStorage.
  2. Добавьте валидацию ввода (не пустая строка, ограничение длины).
  3. Покройте сценарии: добавление, удаление, редактирование, перезагрузка страницы.
  4. Добавьте тесты приёмки (см. раздел Критерии приёмки).
  5. Переходите к объектной модели задач и синхронизации с сервером по мере необходимости.

Когда такая реализация не подойдёт

  • Приложение требует совместной работы нескольких пользователей — localStorage не подходит.
  • Большой объём данных и необходимость поиска/фильтрации на сервере — нужна база данных.
  • Высокие требования по безопасности и аудиту — нужен серверный слой и авторизация.

Альтернативные подходы

  • Хранение на сервере через REST API или GraphQL.
  • Использование IndexedDB для оффлайн‑вместимости и больших объёмов данных.
  • Использование фреймворков (React/Vue/Svelte) для сложного UI и управляемого состояния.

Практические эвристики и ментальные модели

  • Single source of truth: одна структура состояния (например, todoArray) и её последовательная сериализация в localStorage.
  • UI как представление состояния: изменяйте только состояние, затем перерисовывайте представление через displayTodo.
  • Минимальные атомарные операции: каждая кнопка выполняет одну понятную операцию (add/edit/delete/save).

Контрольный список ролей

  • Разработчик: сделать валидацию, обработать ошибки парсинга JSON, учесть пустые значения.
  • Тестировщик: проверить сценарии добавления/редактирования/удаления и устойчивость UI при непредвидённых данных.
  • Дизайнер: обеспечить доступность кнопок и текстовых полей, добавить фокус и aria‑атрибуты.

Критерии приёмки

  • При добавлении новой задачи она отображается в списке и сохраняется после перезагрузки.
  • При удалении задача исчезает из списка и больше не появляется после перезагрузки.
  • При редактировании изменённый текст сохраняется и отображается корректно.
  • Пустые задачи не добавляются.
  • Интерфейс не ломается при отсутствии данных в localStorage.

Набор тестов и критерии приёмки (коротко)

  1. Добавление: ввести “Купить хлеб”, нажать Add → элемент появляется, localStorage содержит “Купить хлеб”.
  2. Удаление: удалить первый элемент → элемент исчезает, localStorage обновлён.
  3. Редактирование: отредактировать элемент → новое значение появилось и сохранилось.
  4. Перезагрузка: после перезагрузки страницы все изменения сохраняются.

Decision flow: что делать при пустом localStorage (Mermaid)

flowchart TD
  A[Загрузилась страница] --> B{Есть ключ 'todo' в localStorage?}
  B -- Да --> C[Парсить JSON в todoArray]
  B -- Нет --> D[Инициализировать todoArray = []]
  C --> E[Вызвать displayTodo]
  D --> E
  E --> F[Пользователь взаимодействует: add/edit/delete]
  F --> G[Обновить todoArray и localStorage]
  G --> E

Советы по расширению и безопасности

  • Для совместной работы переходите на бэкенд и аутентификацию.
  • Для больших списков используйте виртуальный рендеринг (windowing) или pagination.
  • Всегда проверяйте данные при чтении из localStorage: try/catch при JSON.parse.

Шаблон: расширяемая структура задачи

Рекомендуемая структура для расширения функционала:

// Пример структуры задачи
{
  id: 'uuid-or-timestamp',
  text: 'Описание задачи',
  done: false,
  createdAt: 1670000000000,
  tags: ['важное','дом']
}

При такой структуре проще добавлять метаданные, фильтры и синхронизацию.

Рекомендации по доступности и локализации

  • Добавьте aria‑labels к полям ввода и кнопкам.
  • Используйте семантические теги (ul/li для списка задач) вместо div, если это уместно.
  • Для интернационализации выносите строки в отдельный словарь.

Резюме

Важно помнить: простая реализация на localStorage отлично подходит для личных и учебных проектов. По мере роста требований стоит перенести логику хранения на сервер, улучшить структуру данных и добавить тесты. Начните с базовой модели, затем итеративно улучшайте: валидация, обработка ошибок, доступность и синхронизация.

Важно: регулярное сохранение состояния и единый источник истины (todoArray) упрощают масштабирование приложения.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Как добавлять подписи к фото на iPhone и iPad
Фото

Как добавлять подписи к фото на iPhone и iPad

Как мобильные игры вредят здоровью и что делать
Здоровье

Как мобильные игры вредят здоровью и что делать

Отключить местоположение на Android
Приватность

Отключить местоположение на Android

Обработка RAW с RawTherapee
Фотография

Обработка RAW с RawTherapee

Проверить и сменить разрешение экрана в Windows 10
Windows

Проверить и сменить разрешение экрана в Windows 10

Планирование дня без стресса
Продуктивность

Планирование дня без стресса