Проекты — отличный способ улучшить свои навыки работы с HTML, CSS и JavaScript, обучая ключевым понятиям и практикам.

Книга рецептов, которую вы можете запустить в браузере, таком как Google Chrome или Firefox, — хорошее место для начала.

Книга рецептов имеет место в левой части веб-страницы, где пользователь может вводить новые рецепты.

Пользователь может просматривать и искать существующие рецепты в правой части страницы.

Как запросить новый рецепт у пользователя

Заполните пробелы в файлах HTML, CSS и JavaScript.

Если вы не знакомы с концепциями веб-разработки, в Интернете есть несколько сайтов, которые могут помочь вам изучить веб-разработку.

В новый файл HTML с именем index.html добавьте следующую базовую структуру HTML:

<!DOCTYPE html>
<html>
  <head>
    <title>Recipe App</title>
  </head>
  <body>
    <nav>
      <h1>Recipe App</h1>
    </nav>
    <div class="container">
      <!-- Content here -->
    </div>
  </body>
</html>

Разделите страницу на левый и правый столбцы в классе контейнера:

<div class="left-column">

</div>
<div class="right-column">

</div>

Создайте форму в левом столбце, чтобы пользователь мог ввести новый рецепт.

Пользователь может ввести название рецепта, список ингредиентов и метод:

<h3>Add Recipe</h3>

<form>
  <label for="recipe-name">Name:</label>
  <input type="text" id="recipe-name" required>
  <br />

  <label for="recipe-ingredients">Ingredients:</label>
  <textarea id="recipe-ingredients" rows="5" required></textarea>
  <br />

 <label for="recipe-method">Method:</label>
  <textarea id="recipe-method" rows="5" required></textarea>
  <br />

  <button type="submit">Add Recipe</button>
</form>

Предоставьте такую ​​ссылку на новый файл CSS с именем styles.css в теге заголовка HTML-файла.

Поместите следующий файл в ту же папку, что и ваш HTML-файл:

<link rel="stylesheet" href="styles.css">

Добавьте стиль для всей страницы в файл CSS:

body {
  font-family: sans-serif;
}

nav {
  background-color: #333;
  position: fixed;
  top: 0;
  width: 100%;
  padding: 20px;
  left: 0;
  color: white;
  text-align: center;
}

.container {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  margin: 150px 5%;
}

.left-column {
  width: 25%;
}

.right-column {
  width: 65%;
}

Оформите форму добавления рецептов следующим образом:

form {
  display: flex;
  flex-direction: column;
}

label {
  margin-bottom: 10px;
}

input[type="text"], textarea {
  padding: 10px;
  margin-bottom: 10px;
  border-radius: 5px;
  border: 1px solid #ccc;
  width: 100%;
  box-sizing: border-box;
}

button[type="submit"] {
  padding: 10px;
  background-color: #3338;
  color: #fff;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

Включите ссылку на файл JavaScript с именем script.js в нижней части элемента body в вашем HTML-файле.

Создайте в той же папке следующий файл:

<body>
  <!-- Content -->
  <script src="script.js"></script>
</body>

Используйте метод querySelector в script.js для обхода DOM и получения элемента формы со страницы.

const form = document.querySelector('form');

Создайте новый массив для хранения рецептов, введенных пользователем в форму:

let recipes = [];

Получите имя, ингредиенты и поля метода из формы в новой функции.

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

function handleSubmit(event) {
  // Prevent default form submission behavior
  event.preventDefault();
  
  // Get recipe name, ingredients, and method input values
  const nameInput = document.querySelector('#recipe-name');
  const ingrInput = document.querySelector('#recipe-ingredients');
  const methodInput = document.querySelector('#recipe-method');
  const name = nameInput.value.trim();
  const ingredients = ingrInput.value.trim().split(',').map(i => i.trim());
  const method = methodInput.value.trim();
}

Если входные данные действительны, добавьте их в массив рецептов:

if (name && ingredients.length > 0 && method) {
  const newRecipe = { name, ingredients, method };
  recipes.push(newRecipe);
}

Очистите входные данные формы:

nameInput.value = '';
ingrInput.value = '';
methodInput.value = '';

Добавьте прослушиватель событий после функции handleSubmit() для вызова кода, когда пользователь отправляет форму:

form.addEventListener('submit', handleSubmit);

См. форму слева, открыв index.html в браузере:

Как показать новые рецепты

Рецепты, записанные в массиве рецептов, можно просмотреть в правой части страницы.

Включите div в HTML-код, чтобы отобразить список рецептов в правой колонке.

Добавьте еще один div для отображения сообщения, если рецепты не найдены:

<div class="right-column">
  <div id="recipe-list"></div>
  <div id="no-recipes">You have no recipes.</div>
</div>

Добавьте следующий стиль CSS в список рецептов:

#recipe-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  grid-gap: 20px;
}

#no-recipes {
  display: flex;
  background-color: #FFCCCC;
  padding: 20px;
  border-radius: 8px;
  margin-top: 44px;
}

Получите элементы HTML, используемые для отображения списка рецептов и предупреждения об ошибке в начале файла JavaScript:

const recipeList = document.querySelector('#recipe-list');
const noRecipes = document.getElementById('no-recipes');

Перебрать каждый рецепт в массиве recipes внутри новой функции.

Создайте новый div для каждого рецепта, чтобы показать его:

function displayRecipes() {
  recipeList.innerHTML = '';
  recipes.forEach((recipe, index) => {
    const recipeDiv = document.createElement('div');
  });
}

Чтобы отобразить название, ингредиенты и метод, добавьте некоторый контент в отдельный раздел рецепта.

Кнопка удаления будет частью div. Эта функция будет добавлена ​​в следующих шагах:

recipeDiv.innerHTML = `
  <h3>${recipe.name}</h3>
  <p><strong>Ingredients:</strong></p>
  <ul>
    ${recipe.ingredients.map(ingr => `<li>${ingr}</li>`).join('')}
  </ul>
  <p><strong>Method:</strong></p>
  <p>${recipe.method}</p>
  <button class="delete-button" data-index="${index}">Delete</button>`;

Чтобы стилизовать div, добавьте следующий класс:

recipeDiv.classList.add('recipe');

Добавьте новый элемент div в HTML-элемент recipeList следующим образом:

recipeList.appendChild(recipeDiv);

В файле CSS добавьте следующий стиль для класса:

.recipe {
  border: 1px solid #ccc;
  padding: 10px;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0,0,0,.2);
}

.recipe h3 {
  margin-top: 0;
  margin-bottom: 10px;
}

.recipe ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.recipe ul li {
  margin-bottom: 5px;
}

Проверьте, много ли рецептов. В этом случае скройте сообщение об ошибке:

noRecipes.style.display = recipes.length > 0 ? 'none' : 'flex';

После добавления нового рецепта в массив recipes вызовите новый метод из функции handleSubmit():

displayRecipes();

В браузере перейдите на index.html:

Добавьте рецепты в список, чтобы увидеть, как они отображаются справа:

Как избавиться от рецептов

Рецепты можно удалить, нажав кнопку «Удалить» рядом с инструкциями рецепта.

Примените следующий стиль CSS к кнопке удаления:

.delete-button {
  background-color: #dc3545;
  color: #fff;
  border: none;
  border-radius: 5px;
  padding: 5px 10px;
  cursor: pointer;
}

.delete-button:hover {
  background-color: #c82333;
}

Добавьте в код JavaScript новый метод для удаления рецепта:

function handleDelete(event) {

}

Получите индекс рецепта, на который нажал пользователь, используя событие JavaScript:

if (event.target.classList.contains('delete-button')) {
  const index = event.target.dataset.index;
}

Чтобы удалить выбранный рецепт из массива recipes, используйте индекс:

recipes.splice(index, 1);

Обновите список рецептов, отображаемый на странице:

displayRecipes();

Когда пользователь нажимает кнопку удаления, добавьте прослушиватель событий, который вызывает функцию handleDelete():

recipeList.addEventListener('click', handleDelete);

Запустите браузер и перейдите на index.html. Чтобы увидеть кнопку удаления, добавьте рецепт:

Как искать рецепты

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

Добавьте строку поиска перед списком рецептов в правой колонке:

<div id="search-section">
  <h3>Recipes List</h3>
  <label for="search-box">Search:</label>
  <input type="text" id="search-box">
</div>

Примените следующий стиль CSS к метке панели поиска:

label[for="search-box"] {
  display: block;
  margin-bottom: 10px;
}

Получите HTML-элемент поля поиска в script.js:

const searchBox = document.getElementById('search-box');

Создайте новый массив внутри новой функции, содержащий рецепты, имена которых соответствуют входным данным поиска:

function search(query) {
  const filteredRecipes = recipes.filter(recipe => {
    return recipe.name.toLowerCase().includes(query.toLowerCase());
  });
}

Очистите список рецептов, отображаемый в данный момент на экране:

recipeList.innerHTML = '';

Создайте новый элемент div для каждого отфильтрованного рецепта, который соответствует результату поиска:

filteredRecipes.forEach(recipe => {
  const recipeEl = document.createElement('div'); 
});

Заполните div содержимым HTML для отфильтрованного рецепта:

recipeEl.innerHTML = `
  <h3>${recipe.name}</h3>
  <p><strong>Ingredients:</strong></p>
  <ul>
    ${recipe.ingredients.map(ingr => `<li>${ingr}</li>`).join('')}
  </ul>
  <p><strong>Method:</strong></p>
  <p>${recipe.method}</p>
  <button class="delete-button" data-index="${recipes.indexOf(recipe)}">
    Delete
  </button>`;

Для единообразия используйте один и тот же класс рецепта. Добавьте следующий div в список страницы:

recipeEl.classList.add('recipe');
recipeList.appendChild(recipeEl);

Когда пользователь вводит текст в строку поиска, добавьте прослушиватель событий, который вызывает функцию search():

searchBox.addEventListener('input', event => search(event.target.value));

Чтобы обновить список, очищайте поле поиска внутри метода handleDelete() всякий раз, когда пользователь удаляет элемент:

searchBox.value = '';

Чтобы увидеть новую панель поиска, откройте index.html в веб-браузере и добавьте несколько рецептов:

Чтобы отфильтровать список рецептов, введите название рецепта в строку поиска:

Создание проектов HTML, CSS и JavaScript

В этом проекте показано, как создать внешний интерфейс для простой книги рецептов.

Бэкенд-сервера нет, и приложение не сохраняет данные; если вы перезагрузите страницу, ваши изменения будут стерты.

Одним из таких дополнений является метод сохранения и загрузки данных с помощью localStorage.

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