В современном динамичном мире веб-разработок реализация мощной поисковой функциональности является ключевым моментом, позволяющим значительно повысить удобство работы пользователей и упростить навигацию по большим массивам данных. Если вы хотите добавить возможности живого поиска на свой сайт или в веб-приложение, вы попали по адресу. В этой статье мы рассмотрим все тонкости реализации функции живого поиска с помощью JavaScript.
Независимо от того, являетесь ли вы опытным разработчиком или только начинаете свой путь в кодинге, эта статья призвана предоставить вам общие знания по кодингу и инструменты, необходимые для внедрения живого поиска в ваши проекты. К концу статьи вы будете иметь полное представление о концепциях и методах, позволяющих создавать отзывчивую и интерактивную поисковую функциональность, которая динамически обновляется по мере ввода текста пользователем.
Для эффективной работы с данным руководством рекомендуется хорошо знать основы HTML, CSS и JavaScript. Знакомство с манипуляциями с DOM и обработкой событий будет полезным, когда мы погрузимся в детали реализации. Однако даже если вы относительно недавно знакомы с JavaScript или веб-разработкой, руководство построено таким образом, чтобы обеспечить четкие объяснения и пошаговые инструкции, что делает его доступным для учащихся с различным уровнем подготовки.
Теперь, чтобы лучше понять важность и применение этой функциональности, мы создадим в качестве примера очень простой проект, а точнее, приложение для просмотра фильмов, как показано ниже:
Ознакомиться с живой реализацией можно здесь.
В этом проекте мы будем использовать функцию живого поиска для поиска по списку фильмов из базы данных фильмов. Я знаю, что вам уже не терпится погрузиться в работу; мы уже близко к этому. Но сначала давайте узнаем немного больше о том, что такое функциональность живого поиска и какова ее важность.
Важность функции живого поиска
Функция живого поиска стала жизненно важной в современном цифровом ландшафте, удовлетворяя потребность в эффективном поиске информации и повышая общий уровень обслуживания пользователей. Благодаря возможности обновления поисковой информации в режиме реального времени по мере ввода пользователем текста, живой поиск обеспечивает мгновенную обратную связь и быстрый доступ к необходимой информации. Эта динамичная и интерактивная функция поиска дает множество преимуществ, выгодных как пользователям, так и владельцам сайтов.
- Улучшение качества работы пользователей: Живой поиск значительно повышает удобство работы пользователей, обеспечивая интуитивно понятный процесс поиска. Как только пользователь начинает вводить свой запрос, результат поиска обновляется в реальном времени, обеспечивая мгновенную обратную связь и устраняя необходимость в ручном вводе или перезагрузке страницы. Такая интерактивность позволяет сэкономить время и силы пользователей, что делает поиск более эффективным и приятным.
- Ускоренный поиск информации: Благодаря «живому» поиску пользователи могут быстро находить нужную информацию, не переходя по нескольким страницам и не ожидая загрузки результатов поиска. По мере ввода текста результаты поиска мгновенно сужаются, отображая соответствующие предложения и избавляя от необходимости вводить полный текст поискового запроса. Благодаря такой скорости и оперативности пользователи могут найти то, что им нужно, за долю времени, которое требуется при использовании традиционных методов поиска.
- Увеличение вовлеченности и конверсии: Бесперебойная и оперативная работа живого поиска стимулирует пользователей к более активному взаимодействию с веб-сайтом или веб-приложением. Предоставление мгновенной обратной связи и релевантных предложений поддерживает пользователей, сводя к минимуму вероятность отказов и разочарований. Повышение вовлеченности может привести к повышению конверсии, поскольку пользователи с большей вероятностью будут изучать сайт дальше и конвертировать свои поисковые намерения в действия.
- Усовершенствованная фильтрация и уточнение: Функциональность живого поиска часто включает дополнительные возможности, такие как фильтры, предложения и автозаполнение. Эти функции помогают пользователям уточнить поиск и сузить результаты, что позволяет им найти то, что они ищут. Предоставляя такие инструменты, «живой» поиск улучшает качество поиска, а также помогает пользователям обнаружить связанный контент или продукты, о которых они, возможно, даже не подозревали.
- Ценные сведения для владельцев сайтов: Функциональность живого поиска позволяет получить ценные сведения о поведении и предпочтениях пользователей. Анализируя поисковые запросы и закономерности, владельцы сайтов могут лучше понять, что ищут их пользователи, выявить популярные тенденции или темы, а также принять обоснованные решения по созданию контента, предложению продуктов или улучшению пользовательского интерфейса. Эти данные позволяют владельцам сайтов адаптировать свои предложения к потребностям пользователей, что приводит к повышению удовлетворенности клиентов и росту бизнеса.
Настройка структуры HTML
Теперь, когда мы имеем полное представление о том, что такое функциональность живого поиска и какова ее важность, давайте рассмотрим, как можно реализовать ее и в своем проекте.
Прежде всего, давайте определим структуру проекта. Для этого проекта нам понадобится всего три файла: HTML, CSS и JavaScript.
Начнем с настройки HTML-структуры нашего проекта: В HTML-файл сначала нужно включить стандартный HTML-шаблон, включающий ссылку и скрипт на наши CSS- и JS-файлы:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="./live-search.css" />
<title> </title>
.
</head>
<body>
<script src="./live-search.js"></script>
</body>
</html>
Теперь в тег body
мы включаем семантические теги header
и main
. Внутри тега header
мы задаем заголовок нашего проекта, который в данном случае представляет собой просто название приложения и иконку видео.
<header>
<ion-icon name="videocam"></ion-icon>
<h1>Поиск фильмов</h1>
</header>
Прежде чем перейти к тегу main
, в конце тега body
включим необходимые теги script
для того, чтобы можно было использовать иконки:
<script type="module" src="https://unpkg.com/[email protected]/dist/ionicons/ionicons.esm.js"></script>
<script nomodule src="https://unpkg.com/[email protected]/dist/ionicons/ionicons.js"></script>
Иконки можно найти на сайте Ionicons.
Теперь внутри тега main
мы включим наш первый тег div
, который будет нашим контейнером строки поиска, а внутри него мы разместим наш тег ввода поиска и иконку поиска:
<div id="search-container">
<ion-icon name="search-outline"></ion-icon>
<input type="search" id="search-bar" placeholder="Поиск фильмов..." />
</div>
Затем мы создадим еще один тег div
под этим «div». В нем будут храниться все результаты просмотра фильмов:
<div id="results-container"></div>
Пока оставим его пустым, так как его содержимое будет сгенерировано в разделе JavaScript.
Наконец, в тег main
мы включим тег p
. Этот тег предназначен для последующего отображения ответа на сообщение об ошибке или пустом сообщении.
<p id="movie-unavailable-txt"></p>
Это все для HTML-файла, а общий код должен выглядеть следующим образом:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="./live-search.css" />
<title>Функциональные возможности живого поиска</title>
</head>
<body>
<Заголовок>
<ion-icon name="videocam"></ion-icon>
<h1>Поиск фильмов</h1>
</header>
<main>
<div id="search-container">
<ion-icon name="search-outline"></ion-icon>
<input type="search" id="search-bar" placeholder="Поиск фильмов..." />
</div>
<div id="results-container"></div>
<p id="movie-unavailable-txt"></p>
</main>
<script src="./live-search.js"></script>
<script
type="module"
src="https://unpkg.com/[email protected]/dist/ionicons/ionicons.esm.js"
></script>
<script
nomodule
src="https://unpkg.com/[email protected]/dist/ionicons/ionicons.js"
></script>
</body>
</html>
Теперь, когда мы закончили реализацию HTML-структуры проекта, давайте добавим несколько стилей на страницу.
Добавление стилей на страницу
В этом разделе мы добавим основные стили к различным частям страницы. Поэтому давайте сразу же приступим к работе.
Сначала добавим несколько общих стилей к общей части страницы:
html{ scroll-behavior: smooth; background-color: #111; цвет: белый дым; } *{ margin: 0; padding: 0;
box-sizing: border-box; }
Теперь добавим некоторые стили к разделу заголовка и его содержимому:
header {
display: flex;
justify-content: center;
padding: 25px;
letter-spacing: 2px;
position: sticky;
top: 0%;
z-index: 2;
border-bottom: 2px solid;
background-color: black;
text-shadow: 3px 3px 5px #fd1d6b;
box-shadow: 10px 10px 20px -10px #fd1d6b;
}
header > ion-icon {
color: #fd1d6b;
font-size: 60px;
position: absolute;
left: 5%;
}
Далее мы переходим к стилизации контейнера поиска и его содержимого:
#search-container {
display: flex;
justify-content: center;
padding: 20px;
margin-bottom: 20px;
position: sticky;
top: 100px;
}
#search-bar {
border: none;
ширина: 60%;
padding: 15px;
padding-left: 40px;
border-radius: 15px;
font-size: 15px;
}
#search-container > ion-icon {
цвет: серый;
position: relative;
left: 30px;
top: 13px;
z-index: 3;
font-size: 19px;
}
После этого мы приступаем к созданию стиля results-container
, в котором будут храниться все фильмы, полученные из базы данных фильмов:
#results-container {
border-right: 5px solid #fd1d6b;
border-left: 5px solid #fd1d6b;
border-radius: 25px;
display: flex;
justify-content: center;
flex-wrap: wrap;
width: 90vw;
}
Далее мы добавим стили к movie-unavailable-txt
, установив display
в none
, поскольку пока не хотим, чтобы он был виден:
#movie-unavailable-txt {
text-align: center;
интервалмеждубуквами: 2px;
display: none;
margin-top: 15%;
text-shadow: 3px 3px 5px #fd1d6b;
}
Далее мы добавим стили к нескольким элементам, которые еще не были объявлены, но которые мы создадим с помощью javascript. Это карточка фильма, которая будет отображать подробную информацию о фильме, содержащую изображение и название фильма:
.movie-cards {
padding: 25px;
max-width: 250px;
border-radius: 15px;
display: grid;
place-items: center;
box-shadow: 1px 1px 20px -1px #fd1d6b;
margin: 50px;
}
.title {
margin: 20px auto;
text-align: center;
font-size: 1.2rem;
text-shadow: 3px 3px 5px #fd1d6b;
}
.date {
margin-top: 15px;
font-size: 0.8rem;
text-shadow: 3px 3px 5px #fd1d6b;
}
.movie-image {
width: 90%;
max-width: 400px;
object-fit: contain;
border-radius: 5px;
}
Теперь, когда мы закончили со стилизацией страницы, перейдем к самому интересному и важному разделу — реализации Javascript.
Отправка асинхронных поисковых запросов к API базы данных фильмов.
В этом разделе мы будем выполнять API-вызовы к выбранному нами API базы данных фильмов, чтобы наполнить нашу страницу различными фильмами. В данном случае я буду использовать API бесплатных фильмов IMDb Top 100 Movies в RapidAPI Hub. На странице API мы выбираем конкретные данные, которые хотим использовать, а затем копируем код javascript (fetch), приведенный в правой части страницы для этих данных, как показано ниже:
Но прежде чем использовать API, необходимо подписаться на него (без использования кредитной карты), чтобы для вас был сгенерирован API-ключ. Это можно сделать на странице [pricing page] (https://rapidapi.com/rapihub-rapihub-default/api/imdb-top-100-movies/pricing) API.
Далее мы переходим в наш пустой файл javascript и вставляем туда скопированный нами код:
const url = 'https://imdb-top-100-movies.p.rapidapi.com/';
const options = {
method: 'GET',
headers: {
'X-RapidAPI-Key': 'СГЕНЕРИРОВАННЫЙ ВАМИ API КЛЮЧ',
'X-RapidAPI-Host': 'imdb-top-100-movies.p.rapidapi.com',
},
};
try {
const response = await fetch(url, options);
const result = await response.text();
console.log(result);
} catch (error) {
console.error(error);
}
Теперь, когда мы получили API от базы данных фильмов в наш проект, мы можем использовать ее данные. Для этого объявим несколько необходимых нам переменных и поместим их чуть выше блока try
в скопированном нами коде:
const SearchBar = document.getElementById('search-bar');
const resultsContainer = document.getElementById('results-container');
const movieUnavailableTxt = document.getElementById('movie-unavailable-txt');
let movieList;
let searchValue;
let searchedMovies;
Мы подходим к назначению этих переменных, которые мы только что создали, держитесь.
Далее мы вносим некоторые изменения в блок try
из скопированного кода, поскольку хотим полностью интегрировать его в наш проект. Итак, для начала нам нужно создать асинхронную функцию:
const fetchMovies = async () => {
// блок try catch помещается сюда.
};
Внутри этой функции мы поместим весь блок try
catch
из скопированного нами кода, чтобы иметь возможность осуществлять асинхронные вызовы API.
Внутри блока try
мы избавимся от строки console.log(result)
и изменим переменную result
на переменную movieList
, которую мы объявили ранее, а также изменим response.text()
в этой же строке на response.json()
. Это необходимо для того, чтобы данные, полученные в результате вызова API, были представлены в нужном нам формате JSON
. Теперь эта строка должна выглядеть следующим образом:
movieList = await response.json();
Теперь, когда мы успешно извлекли фильм из API и вернули набор данных JSON
, нам необходимо заполнить этими данными нашу страницу. Для этого мы вызовем функцию renderMovies()
и установим в качестве аргумента данные, полученные в результате обращения к API. Не волнуйтесь, мы скоро создадим эту функцию:
renderMovies(movieList);
Теперь создадим функцию renderMovies
, которую мы только что вызвали в функции fetchMovies()
. С помощью этой функции мы создадим динамический шаблон карточки фильма, стили для которого мы задали ранее в нашем CSS-файле, а в каждом из элементов шаблона мы зададим их содержимое данными, полученными из API, что позволит нам отображать разные фильмы с помощью одного и того же шаблона. Затем мы поместим карточку фильма внутрь элемента resultsContainer
. При каждом вызове функции необходимо очищать resultsContainer
, устанавливать moviesUnavailableTxt
в значение display="none"
, поскольку мы хотим, чтобы текст не был виден при выводе фильмов на страницу, а также очищать массив moviesReturnedOnSearch
, прежде чем поместить в него новые данные, возвращенные из поля ввода поиска:
const renderMovies = (movies) => {
resultsContainer.innerHTML = ''; // Очищаем существующие фильмы
movieUnavailableTxt.style.display = 'none'; // Скрыть сообщение "Фильмы не найдены"
moviesReturnedOnSearch = []; // Очистить массив фильмов, возвращенных при поиске
movies.forEach((movie) => {
resultsContainer.innerHTML += `
<div class="movie-cards">
<img src="${movie.image}" alt="изображение фильма" class="movie-image" />
<h2 class="title">${movie.title}</h2>
<p class="plot">${movie.description}</p>
<p class="date">${movie.year}</p>
</div>
`;
moviesReturnedOnSearch.push(movie); // Добавляем фильмы, ставшие результатом поиска, во входное значение поиска
});
};
Перехват пользовательского ввода и отображение результатов поиска фильмов в реальном времени
Теперь, когда мы загрузили все данные о фильмах на нашу страницу, начинается самая интересная часть, в которой мы реализуем функцию поиска в реальном времени, поэтому, не теряя времени, давайте сразу же приступим к работе.
Для перехвата пользовательского ввода мы будем использовать слушатель событий input
и привяжем его к элементу searchBar
. Мы используем именно этот приемник событий, поскольку он фиксирует все действия внутри поисковой строки — от ввода до очистки и вставки, что как раз то, что нам нужно. Поэтому давайте создадим его:
searchBar.addEventListener('input', (event) => {
// живой код функциональности
});
Итак, мы подключили к строке поиска слушатель события input
, который будет воспринимать любой ввод от пользователя. Во втором параметре мы добавили обработчик события — функцию, которая будет вызываться каждый раз, когда в строку поиска будет введен хоть один элемент. Теперь внутри этой функции мы создадим код, который будет обрабатывать живой поиск.
Первое, что нам нужно сделать внутри функции поиска, — это отредактировать значение ввода, полученное от пользователя, и установить его во все строчные буквы, а также избавиться от лишних пробелов:
searchValue = event.target.value.trim().toLowerCase();
После этого мы приступаем к фильтрации фильмов на странице по названию, основываясь на поисковом вводе пользователя, проверяя, включает ли в себя название фильма, введенное пользователем, любое из названий фильмов в данных movieList
, а также устанавливая названия фильмов в нижний регистр, чтобы соответствовать вводу пользователя:
const filteredMovies = movieList.filter((movie) => movie.title.toLowerCase().includes(searchValue));
Далее мы выводим результаты поиска фильмов в реальном времени, отображая название фильма, соответствующее символам, которые пользователь набрал в строке поиска, еще раз вызывая функцию renderMovies()
и устанавливая в качестве аргументов значения переменной filtered Movies
.
renderMovies(filteredMovies);
Вызов этой функции позволяет вывести на страницу только те фильмы, названия которых совпали с символами, введенными в строку поиска с помощью шаблона карточки фильма, представленного в функции, а также добавить каждый из совпавших фильмов в массив moviesReturnedOnSearch
, что позволяет отслеживать, сколько фильмов совпало с поисковым значением при вводе каждого символа. Это будет полезно при обработке ошибок пустого ответа, чем мы сейчас и займемся.
Обработка пустых или ошибочных ответов
В любом приложении эффективная обработка пустых ответов или ответов с ошибками крайне важна. В данном случае такие сценарии могут возникать, когда поисковый запрос не дает никаких результатов или возникают проблемы с API-запросом.
Для обработки ошибок или пустых ответов необходимо обеспечить четкую обратную связь с пользователем. При этом, поскольку это довольно легкое приложение, нам не нужно беспокоиться о большом количестве ошибок, поскольку мы будем иметь дело только с ошибками, возникающими при работе с API. Например, сервисы API могут быть временно отключены, или приложение просто превысило лимит запросов. Для обработки этой ошибки нам достаточно установить display
элемента movieUnavailableTxt
в block
и установить innerHTML
для отображения сообщения об ошибке пользователю и поместить его внутри блока catch
функции fetchMovies()
. Теперь блок catch
выглядит следующим образом:
catch (error) {
movieUnavailableTxt.innerHTML = 'При получении фильмов произошла ошибка. <br /> Пожалуйста, повторите попытку позже.'
movieUnavailableTxt.style.display = "block";
console.error(error);
}
Теперь, когда мы закончили работу с ответом на ошибку, перейдем к работе с пустым ответом. Если фильм, который ищет пользователь, не совпадает ни с одним из фильмов на странице, то необходимо предупредить пользователя о том, что искомый фильм недоступен. Для этого сначала нужно проверить содержимое массива moviesReturnedOnSearch
, который мы объявили ранее, и если длина массива меньше или равна 0, то установить display
элемента movieUnavailableTxt
в block
и установить innerHTML
в пустое сообщение ответа, которое мы хотим отобразить, как показано ниже:
if (moviesReturnedOnSearch.length <= 0) {
movieUnavailableTxt.innerHTML = 'OOPS! <br/><br/> Фильм недоступен';
movieUnavailableTxt.style.display = 'block'; // Показать сообщение "Фильмы не найдены", если ни один фильм не соответствует поиску
}
Этот блок if
мы поместим непосредственно перед закрывающей скобкой обработчика события searchBar
.
Повышение производительности поиска с помощью кэширования
При реализации функции живого поиска с помощью API одним из эффективных методов повышения производительности является кэширование. Кэширование подразумевает хранение ранее полученных результатов поиска и их повторное использование при повторном запросе того же поискового запроса. Это позволяет значительно сократить количество обращений к API, что поможет избежать превышения лимита запросов API и в целом улучшить отзывчивость функции поиска, а также время загрузки сайта.
Чтобы реализовать кэширование в нашем проекте, сначала нужно определить, какой элемент необходимо кэшировать, и в данном случае это будет значение переменной movieList
, которая представляет собой данные, полученные нами в результате API-запроса fetch
в формате JSON
. Кэширование этого элемента позволит нам использовать данные API без дополнительного запроса fetch
, даже при перезагрузке страницы. Но для данного проекта мы установим срок действия кэшированных данных в 6 часов, то есть страница будет запрашивать API только раз в 6 часов, а не при каждой перезагрузке страницы. Это необходимо для того, чтобы страница могла сохранять свежесть и актуальность своих данных, а количество запросов к API было минимальным.
Возвращаясь к нашему коду, отметим, что теперь нам необходимо сохранить данные JSON
в локальном хранилище браузера, но для этого нужно сначала превратить их в строку
и задать имя ключа, который будет использоваться для идентификации данных в локальном хранилище. Зададим его как movieData
, как показано ниже:
localStorage.setItem('moviedata', JSON.stringify(movieList));
Следующее, что нам нужно сделать, это сохранить текущую дату и время в локальном хранилище:
localStorage.setItem('cacheTimestamp', Date.now());
Здесь хранится текущая дата и время в миллисекундах с ключевым именем cacheTimeStamp
.
Эти две строки кода мы поместим в блок try
функции fetchMovies()
, прямо под переменной movieList
.
Далее, вне функции fetchMovies()
, чуть ниже функции renderMovies()
, мы установим время истечения кэшированных данных равным 6 часам в миллисекундах:
const expirationDuration = 21600000; // 6 часов в миллисекундах
После этого нам необходимо получить обратно cacheTimestamp
, который мы ранее установили в локальном хранилище:
const cacheTimestamp = localStorage.getItem('cacheTimestamp');
Теперь мы проверим, не истек ли срок действия кэшированных данных или они недоступны, т. е. еще не были сохранены. Если это так, то мы сделаем новый запрос fetch
к API, вызвав функцию fetchMovies()
. С другой стороны, если кэшированные данные присутствуют и срок их хранения еще не истек, мы используем их для отображения фильмов на странице, а не делаем новый запрос fetch
. Для этого мы извлекаем кэшированные данные о фильмах и разбираем их в формат JSON
, а затем вызываем функцию render
с аргументом, равным данным, полученным из кэша.
// Проверяем, не истек ли срок действия кэша или не доступны ли данные
if (!cacheTimestamp || Date.now() - parseInt(cacheTimestamp) > expirationDuration) {
// Срок действия кэша истек или данные недоступны, выполните повторную выборку фильмов
fetchMovies();
} else {
// Используем кэшированные данные о фильмах
movieList = JSON.parse(localStorage.getItem('moviedata'));
renderMovies(movieList);
}
В операторе if
переменная !cacheTimestamp
проверяет, является ли переменная cacheTimestamp
фальшивой, то есть равна ли она null
, undefined
, 0, false
или пустой строке. Если cacheTimestamp
равна false, то это означает, что в кэше не хранится ни одной существующей временной метки. Функция Date.now() - parseInt(cacheTimestamp)
вычисляет разницу во времени между текущей временной меткой и разобранным целочисленным значением cacheTimestamp
. Таким образом, мы просто говорим: «Значение текущего времени минус значение времени, которое мы ранее хранили в кэше, больше ли оно, чем установленное нами время истечения? Если да, то давайте снова получать фильмы из API, а если нет, то просто воспользуйтесь кэшированными данными».
Вот так мы кэшируем данные для повторного использования, а не выполняем запрос fetch
при каждом вводе пользователя или при каждой перезагрузке страницы. Как видите, это значительно оптимизирует работу приложения, так как предотвращает медленный рендеринг фильма, который может происходить из-за медленной сети.
На этом мы закончили реализацию всех функций в нашем небольшом приложении, демонстрирующем работу функции живого поиска. Ниже приведен общий код javascript для этого приложения:
const url = 'https://imdb-top-100-movies.p.rapidapi.com/';
const options = {
method: 'GET',
headers: {
'X-RapidAPI-Key': 'Ваш сгенерированный API-ключ',
'X-RapidAPI-Host': 'imdb-top-100-movies.p.rapidapi.com',
},
};
const SearchBar = document.getElementById('search-bar');
const resultsContainer = document.getElementById('results-container');
const movieUnavailableTxt = document.getElementById('movie-unavailable-txt');
let movieList;
let searchValue;
let moviesReturnedOnSearch;
// Функция для получения фильмов из API
const fetchMovies = async () => {
try {
const response = await fetch(url, options);
movieList = await response.json();
// Хранение данных о фильмах в хранилище браузера
localStorage.setItem('moviedata', JSON.stringify(movieList));
localStorage.setItem('cacheTimestamp', Date.now()); // Обновление временной метки кэша
// Рендеринг фильмов на странице
renderMovies(movieList);
} catch (error) {
movieUnavailableTxt.innerHTML =
'Произошла ошибка при получении фильмов. <br /> Пожалуйста, повторите попытку позже.';
movieUnavailableTxt.style.display = 'block';
console.error(error);
}
};
// Функция для вывода фильмов на страницу
const renderMovies = (movies) => {
resultsContainer.innerHTML = ''; // Очистка существующих фильмов
movieUnavailableTxt.style.display = 'none'; // Скрыть сообщение "Фильмы не найдены"
moviesReturnedOnSearch = []; // Очистить массив фильмов, возвращенных при поиске
movies.forEach((movie) => {
resultsContainer.innerHTML += `
<div class="movie-cards">
<img src="${movie.image}" alt="изображение фильма" class="movie-image" />
<h2 class="title">${movie.title}</h2>
<p class="plot">${movie.description}</p>
<p class="date">${movie.year}</p>
</div>
`;
moviesReturnedOnSearch.push(movie); // Добавляем фильмы, ставшие результатом поиска, во входное значение поиска
});
};
const cacheTimestamp = localStorage.getItem('cacheTimestamp');
const expirationDuration = 21600000; // 6 часов в миллисекундах
// Проверяем, истек ли срок действия кэша или данные недоступны
if (!cacheTimestamp || Date.now() - parseInt(cacheTimestamp) > expirationDuration) {
// Срок действия кэша истек или данные недоступны, выполните повторную выборку фильмов
fetchMovies();
} else {
// Используем кэшированные данные о фильмах
movieList = JSON.parse(localStorage.getItem('moviedata'));
renderMovies(movieList);
}
// Слушатель и обработчик событий для ввода строки поиска
searchBar.addEventListener('input', (event) => {
searchValue = event.target.value.trim().toLowerCase();
// Отфильтровать фильмы на основе поисковых данных
const filteredMovies = movieList.filter((movie) =>
movie.title.toLowerCase().includes(searchValue),
);
// Отображение отфильтрованных фильмов на странице
renderMovies(filteredMovies);
if (moviesReturnedOnSearch.length <= 0) {
movieUnavailableTxt.style.display = 'block'; // Показываем сообщение "Фильмы не найдены", если ни один фильм не соответствует поиску
}
});
Заключение
В этом руководстве мы рассмотрели реализацию функциональности живого поиска на JavaScript с использованием API. Выполнив описанные шаги, можно создать динамический поиск, который будет выдавать результаты в реальном времени по мере ввода пользователем текста в строке поиска.
Внедрив функцию живого поиска на свой сайт, вы сможете повысить вовлеченность пользователей и улучшить удобство использования вашего сайта или приложения. Пользователи оценят возможность быстрого и удобного поиска нужной информации без необходимости перезагрузки страницы.
Благодаря знаниям, полученным из этого руководства, вы сможете эффективно реализовать функциональность живого поиска на JavaScript. Воспользуйтесь возможностями динамического поиска и создайте удобную систему, которая произведет неизгладимое впечатление на пользователя.
Счастливого кодирования!