Понимание основ

Создание менеджера закладок с JavaScript и API Web Storage - отличный проект для освоения фундаментальных концепций интерфейса. По своей сути приложение должно обрабатывать три основные операции: , , , , и , удалить - классический шаблон CRUD, минус обновления на данный момент. Данные живут в локальном хранилище браузера , позволяя закладкам сохраняться в течение сессий без сервера.

Прежде чем писать одну строку кода, укрепите свое понимание следующих столпов:

  • DOM API: Вы будете запрашивать элементы, слушать события и манипулировать деревом документов, чтобы динамически отображать закладки.
  • localStorage: Этот хранилище ключевых значений сохраняет данные даже после закрытия браузера. Он поддерживает только строки, поэтому объекты должны быть сериализованы с и десериализированы с .
  • Программирование на основе событий: Формы испускают события; удаляют кнопки, зажигающие события. Освоение не подлежит обсуждению.
  • Методы массива: , и помогут эффективно отображать и манипулировать списком закладок.

Создание Core Bookmark Manager

HTML структура

Начните с минимального семантического HTML-скелета. Форма собирает имя закладки и URL; неупорядоченный список отображает сохраненные закладки.

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Bookmark Manager</title>
</head>
<body>
 <h1>My Bookmarks</h1>
 <form id="bookmarkForm">
 <label for="name">Name</label>
 <input type="text" id="name" required />
 <label for="url">URL</label>
 <input type="url" id="url" required />
 <button type="submit">Add Bookmark</button>
 </form>
 <ul id="bookmarkList"></ul>
 <script src="app.js" defer></script>
</body>
</html>

Обратите внимание на атрибут на теге сценария — он гарантирует, что DOM полностью разбирается перед запуском сценария, устраняя необходимость в обертке в современных настройках.

Стилизованный для удобства использования (необязательно, но рекомендуется)

Хотя CSS не является фокусом, чистый интерфейс улучшает пользовательский опыт. Добавьте простой таблицу стилей, чтобы разобрать форму, придать кнопкам последовательный вид и стиль закладок с эффектами наведения. Минимальный встроенный стиль также может быть введен через JavaScript, но для удобства обслуживания предпочтительнее отдельный .

<!-- inside <head> -->
<link rel="stylesheet" href="style.css" />

В используйте флексбокс для макета формы, максимальной ширины для контейнера и четкой визуальной обратной связи для кнопок удаления, чтобы предотвратить случайные щелчки.

Логика JavaScript – сердце приложения

Вся настойчивость и интерактивность живут в . Следующие разделы разбивают каждую функцию.

Инициализация данных

Нам нужна центральная переменная, держащая текущий список закладок. Она должна быть инициализирована из или вернуться к пустому массиву.

let bookmarks = [];

function loadBookmarks() {
 const stored = localStorage.getItem('bookmarks');
 if (stored) {
 bookmarks = JSON.parse(stored);
 } else {
 bookmarks = [];
 }
}

function saveBookmarks() {
 localStorage.setItem('bookmarks', JSON.stringify(bookmarks));
}

loadBookmarks();

Функция называется каждый раз, когда массив изменяется — после добавления, редактирования или удаления закладки. Это гарантирует, что хранилище всегда синхронизируется с массивом в памяти.

Отображение закладок

Передача списка закладок означает повторение над массивом и создание элементов списка с якорной меткой и кнопкой удаления.

function renderBookmarks() {
 const list = document.getElementById('bookmarkList');
 list.innerHTML = ''; // clear existing entries

 bookmarks.forEach(function(bookmark, index) {
 const li = document.createElement('li');
 li.dataset.index = index;

 const link = document.createElement('a');
 link.href = bookmark.url;
 link.textContent = bookmark.name;
 link.target = '_blank';
 link.rel = 'noopener noreferrer';

 const deleteBtn = document.createElement('button');
 deleteBtn.textContent = 'Delete';
 deleteBtn.addEventListener('click', function() {
 deleteBookmark(index);
 });

 li.appendChild(link);
 li.appendChild(deleteBtn);
 list.appendChild(li);
 });
}

Использование вместо внутреннего HTML позволяет избежать уязвимостей XSS, когда имена закладок содержат HTML. Кнопка удаления использует закрытие для захвата индекса закладки.

Добавить закладку

Слушайте событие формы , предотвращайте перезагрузку страницы по умолчанию, создайте объект закладки, подтолкните его к массиву, сохраняйте и перезадавайте.

document.getElementById('bookmarkForm').addEventListener('submit', function(e) {
 e.preventDefault();

 const nameInput = document.getElementById('name');
 const urlInput = document.getElementById('url');

 const newBookmark = {
 name: nameInput.value.trim(),
 url: urlInput.value.trim()
 };

 // Basic validation: ensure URL starts with http/https
 if (!newBookmark.url.startsWith('http://') && !newBookmark.url.startsWith('https://')) {
 newBookmark.url = 'https://' + newBookmark.url;
 }

 bookmarks.push(newBookmark);
 saveBookmarks();
 renderBookmarks();

 // Reset form
 nameInput.value = '';
 urlInput.value = '';
 nameInput.focus();
});

Для производства вы можете проверить формат URL, используя конструктор или регекс.

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

Удаление удаляет элемент в данном индексе и обновляет хранилище и DOM.

function deleteBookmark(index) {
 bookmarks.splice(index, 1);
 saveBookmarks();
 renderBookmarks();
}

Если вы предпочитаете неизменяемость, вы можете использовать и переназначить , но для небольшого проекта, подобного этому, является ясным и исполнителем.

Усовершенствование приложения

После того, как базовый CRUD работает, рассмотрите эти улучшения, чтобы превратить прототип в надежный инструмент.

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

Заменить статическое имя/ссылку режимом встроенного редактирования. При нажатии пользователем кнопки редактирования поменять якорный тег на поля ввода, предварительно заполненные текущими значениями. На сохранение, обновление массива и сохранение.

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

Категоризация с тегами

Добавьте дополнительное свойство к каждому объекту закладки (например, ). Затем расширьте пользовательский интерфейс с помощью входного фильтра, который скрывает элементы списка, теги которых не совпадают. Вы можете хранить теги в виде выделенной запятой строки внутри формы и разделить их на массив.

Импорт и экспорт

Разрешить пользователям резервное копирование или передачу закладок. Используйте или загрузку файла. Экспорт сериализует в строку JSON и запускает загрузку через и . Импорт читает JSON и сливается с существующими закладками.

function exportBookmarks() {
 const data = JSON.stringify(bookmarks, null, 2);
 const blob = new Blob([data], { type: 'application/json' });
 const url = URL.createObjectURL(blob);
 const a = document.createElement('a');
 a.href = url;
 a.download = 'bookmarks.json';
 a.click();
 URL.revokeObjectURL(url);
}

Поиск и фильтр

Добавьте ввод выше списка закладок. На каждом событии отфильтровывайте массив по имени (или URL) и называйте вариант , который отображает только совпадения. Чтобы избежать потери первоначального списка, храните отфильтрованную копию или используйте вычисленный параметр.

Тестирование и совместимость браузера

LocalStorage поддерживается во всех современных браузерах, но более старые версии Internet Explorer (IE 8+) имели другой API. Если вам необходимо поддерживать устаревшие среды, тестируйте с полифиллами или возвращайтесь к файлам cookie. Сегодняшние Chrome, Firefox, Safari, Edge (как Chromium, так и legacy) обрабатывают и без проблем.

При тестировании проверьте:

  • Данные выживают после обновления страницы и перезапуска браузера.
  • Удаление закладки обновляет как пользовательский интерфейс, так и хранилище.
  • Специальные символы в закладочных именах (цитатах, амперсандах) отображаются правильно.
  • URL с и без являются нормализованными.

Используйте инструменты разработчика > Application > Storage > Local Storage для ручного контроля сохраненных данных.
Для автоматизированного тестирования рассмотрите возможность использования Cypress или Playwright для имитации рабочих процессов пользователя — заполните форму, добавьте, удалите, перезагрузите — и утверждайте, что список сохраняется.

Заключение

Этот проект демонстрирует, как несколько десятков строк ванильного JavaScript могут создать полностью функциональное, постоянное веб-приложение. Вы научились использовать API localStorage для сохранения данных, делегирование событий для эффективных обновлений пользовательского интерфейса и CRUD-операции без бэкэнда. Применяемый вами шаблон — инициализация состояния из хранилища, мутация состояния через функции и повторное воспроизведение DOM — является основой многих современных интерфейсных фреймворков, таких как React или Vue.

Чтобы углубить свое понимание, изучите документацию MDN по локальному хранению и прочитайте о обработке событий в DOM . Для более продвинутого управления состоянием, взгляните на IndexedDB для больших наборов данных или сервисных работников для офлайн-первого опыта. С этими строительными блоками вы можете теперь расширить своего менеджера закладок в полноценную личную базу знаний.