Для сегодняшнего веселого приключения мы создадим нашу собственную страницу результатов с бесконечной прокруткой для данных из tmdb API.

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

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

Что вам понадобится:

— ключ API от tmdb. Просто зайдите туда, зарегистрируйте учетную запись, получите ключ API (это бесплатно!) и сразу же возвращайтесь. Я подожду.

Хорошо, отлично! Теперь давайте творить!

Что мы собираемся сделать, так это получить доступ к фильмам текущего года из API. Затем мы распечатаем постер каждого фильма на экране. Когда пользователь прокручивает страницу вниз, мы будем использовать это, чтобы инициировать другой вызов API, чтобы получить больше результатов и просто добавить их к выходным данным.

Если вы когда-нибудь задавались вопросом, почему так много API в настоящее время возвращают результаты с жестким максимальным ограничением в 20 записей или около того, это потому, что этот метод настолько прост в реализации, что на самом деле проще просто сделать это так, чем возиться с нумерацией страниц.

Сначала мы собираемся создать html веб-страницу для вывода наших результатов. Я держу здесь все голые кости, чтобы вы могли просто сосредоточиться на соответствующих товарах:

<!DOCTYPE html>
<html>
<head>
<style>
#output {
width:50%;
margin-left:auto;
margin-right: auto;
margin-top: 20px;
}
</style>
</head>
<body>
<div id=”output”></div>
<script src=”main.js”></script>
</body>
</html>

Да, это целая страница. Просто большой пустой div в середине страницы. Вот что такое «ширина: 50%; поле слева: авто; поле справа: авто;» в стиле говорит это делать.

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

Очевидно, что из тега «script» в коде мы будем называть наш файл Javascript «main.js», поэтому давайте начнем с него сейчас.

Сначала нам нужно настроить наши глобальные переменные:

// you’re going to need your own API key that
// you can get from https://www.themoviedb.org
let APIkey = your API key here;
// we always start at the first page of data results
let pageNum = 1;
// So we can store our movie details when they’re loaded
// and not have to call the API every time
let movies = [];
// for our example we’ll just use movies from 2020
// but you can make this a variable that the user
// can change
let year = 2020;

Далее мы настроим вызов функции для получения одного набора результатов из API. Они отправляются только с 20 записями за раз, поэтому мы будем часто вызывать эту функцию:

const getMoviesByYear = (year,page) => {
// when the user changes genres or year, we need to clear
// the movies array out instead of just filtering
// so it doesn’t add the same movie twice
if (page===1) {movies=[];}
// url to the API
let url = `https://api.themoviedb.org/3/discover/movie?api_key=${APIkey}&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&primary_release_year=${year}&page=${page}`;
// we’re going to build some HTML for the output
let htmlStr = “”;
// the root path to the image files
let imgPath = `https://image.tmdb.org/t/p/w154/`;
fetch(url)
.then(results => results.json())
    .then(data => {
            for (let i = 0;i<data.results.length;i++){
                if (data.results[i].poster_path) {
                    movies.push(data.results[i]);
                    htmlStr+=`<div style=”float:left;”><img src=”${imgPath}${data.results[i].poster_path}” style=”height:230px;width:154px;border-radius:5%;”></div>`;
                }
            }
document.getElementById(“output”).innerHTML+= htmlStr;
})
}

Так. Что происходит в этой функции?

Я начал с этой строки

if (page===1) {movies=[];}

чтобы дать вам представление о некоторых вещах, которые вы можете сделать со всеми этими восхитительными данными. В случае с Flix я сохраняю все данные результатов из API в массив фильмов. Таким образом, у меня все еще есть доступ ко всем импровизированным данным, которые я не показываю в данный момент.

Тот факт, что мы показываем только изображение плаката, не означает, что в результатах нет безумного количества других полезных данных. Вы заметите, что чуть дальше в этой функции я добавляю каждый новый объект фильма в массив:

movies.push(data.results[i]);

Затем мы даем ему URL-адрес конечной точки API, которая дает нам результаты. Помните, что API tmdb предоставляет наборы результатов только из 20 элементов, но также отслеживает для вас текущую страницу этих элементов. Итак, URL-адрес нашего API выглядит так:

let url = `https://api.themoviedb.org/3/discover/movie?api_key=${APIkey}&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&primary_release_year=${year}&page=${page}`;

Как видите, мы также сначала сортируем его по самым крутым фильмам, отфильтровывая pr0n и фильмы с видео. Все это и другие классные параметры вы можете найти в документации по API. Он предоставляет довольно исчерпывающие данные.

Обратите внимание на часть, в которой говорится:

primary_release_year=${year}&page=${page}

${year} и ${page} — это литералы шаблонов, которые включают параметры year и page из вызова функции в URL-адрес.

Следующие строки в значительной степени наизусть:

fetch(url)
.then(results => results.json())
    .then(data => {

Мы извлекаемAPI по URL-адресу, затем называем результаты результаты и преобразовываем их в массив JSON, который мы называем данными.

Вот суть функции:

for (let i = 0;i<data.results.length;i++){
     if (data.results[i].poster_path) {
         movies.push(data.results[i]);
         htmlStr+=`<div style=”float:left;”><img src=”${imgPath}${data.results[i].poster_path}” style=”height:230px;width:154px;border-radius:5%;”></div>`;
                }
            }

Мы прокручиваем наш массив data. Оператор «if» предназначен для фильтрации только тех элементов, которые на самом деле имеют изображение плаката, поэтому мы не получаем кучу пустых пространств с «X» в них там, где отсутствуют плакаты.

Возможно, вы захотите предоставить какое-то альтернативное изображение для таких случаев, чтобы вы могли предоставить пользователю данные о фильме, даже если нет постера, но в этом примере мы полностью обрезаем его, если постера нет.

Затем мы добавляем этот конкретный элемент данных в наш собственный массив:

movies.push(data.results[i]);

Теперь у нас есть копия результатов API в памяти браузера, которую мы можем использовать позже.

Наконец, мы создаем HTML-код, который мы собираемся добавить на нашу страницу для отображения каждого постера:

htmlStr+=`<div style=”float:left;”><img src=”${imgPath}${data.results[i].poster_path}” style=”height:230px;width:154px;border-radius:5%;”></div>`;

Мы помещаем каждый постер в элемент DIV, смещая их все влево, пока они не начнут сворачивать экран — потому что DIV, в котором они находятся, имеет ширину всего 50% — и мы придаем им привлекательный закругленный угол, чтобы они Выглядит круто:

border-radius:5%;

Этот цикл создает весь HTML-код для создания блока div с 20 постерами, но мы еще не отобразили его на экране. Мы делаем это с помощью этой последней строки:

document.getElementById(“output”).innerHTML+= htmlStr;

И вот вы выбрали API, получили результаты и отобразили их на экране. Вы можете видеть, что мы используем оператор «+=» для добавленияновых результатов в наш выходной DIV, а не просто заменяем содержимое с помощью «=».

Теперь давайте сойдем с ума и загрузим больше результатов, когда пользователь прокручивает все текущие!

Нам нужно настроить нашу функцию бесконечной прокрутки. Давайте назовем его описательным, например infiniteScroll, и сделаем его примерно таким:

// this event-handler checks if the scrollbar is at the
// bottom of the page and if it is it fetches another
// set of records
let isScrolled=false;
const infiniteScroll = () => {
// End of the document reached?
if (window.scrollY > (document.body.offsetHeight — 100) && !isScrolled) {
// Set “isScrolled” to “true” to prevent further execution
isScrolled = true;
// Your code goes here
pageNum++;
getMoviesByYear(year, pageNum);
// After 1 second the “isScrolled” will be set to “false” to allow the code inside the “if” statement to be executed again
setTimeout(() => {
isScrolled = false;
}, 1000);
}
}

Вот сложная часть:

if (window.scrollY > (document.body.offsetHeight — 100) && !isScrolled) {

window.scrollY — это свойство, доступное только для чтения, которое возвращает точное местоположение (с точностью до десятичной точки), где в данный момент находится полоса прокрутки.

document.body.offsetHeight — это фактическая высота тела, включая отступы и границы, но не поля.

Существует около 20 различных конфигураций свойств DOM, которые вы можете сравнить, чтобы принять это решение.

* большая проблема для проекта, подобного этому, возникает, когда ваш бесконечный скроллер выполняется на глубоко вложенном DIV и должен приспосабливаться к CSS всех окружающих элементов отображения **

Итак, если это условие выполнено, мы устанавливаем для нашей переменной isScrolled значение «true». Мы делаем это, чтобы он не просто мгновенно продолжал выполнять все больше и больше вызовов выборки. В конечном итоге мы собираемся заставить его ждать секунды между вызовами.

Верно. Мы должны замедлить его, потому что он попытается загрузить больше данных слишком быстро. Вот как вы начинаете сталкиваться с ошибкой 429: «Слишком часто используем наш API!»

Поскольку мы хотим загрузить больше данных, нам потребуется получить URL-адрес API для следующего набора из 20 результатов, поэтому мы увеличиваем нашу глобальную переменную pageNum и снова вызываем нашу процедуру выборки.

pageNum++;
getMoviesByYear(year,pageNum);

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

На этом этапе, если вы загрузите свою страницу в браузер, ничего не произойдет. Вот почему нам нужно настроить наши первоначальные вызовы и обработчики событий. Это также последняя часть головоломки!

// bind the infinite scroll to all needed events
window.onscroll= function() {infiniteScroll();}
// everything starts here!
window.onload = () => {
    getMoviesByYear(year,pageNum)
}

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

window.onscroll= function() {infiniteScroll();}

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

window.onload = () => {
    getMoviesByYear(year,pageNum);
}

Теперь, если вы откроете свою страницу в браузере, вы должны с удовольствием смотреть на это:

Помните, как вы получаете только 20 результатов от каждого вызова API для tmdb? На изображении уже показано 12, но по полосе прокрутки вы можете сказать, что я уже прокрутил некоторые из них, и было получено и добавлено гораздо больше данных.

так интересно

Бесконечная прокрутка — это забавный и фантастический — и простой (!) — способ предоставить вашему пользователю бесшовный интерфейс для данных, которые ему нужны. Вы можете узнать некоторые сайты, которые уже используют этот метод, такие как Facebook, Reddit, Twitter и так далее.

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

нм… вот один сейчас.