Главная » Статьи » Галерея изображений Instagram для сайта с Vue.js и CSS Grid

Галерея изображений Instagram для сайта с Vue.js и CSS Grid

Галерея изображений Instagram для сайта с Vue.js и CSS Grid

От автора: недавно мой клиент запросил создание простой галереи изображений для сайта — тот, который отобразит ее фид Instagram. Я подумал: «Нет проблем, Instagram, безусловно, имеет простой API, и этот прецедент, вероятно, является их самым основным пример Hello World!». Однако, просматривая документацию Instagram API, которая практически не содержит реальных примеров кода, только сбиваешься с толку. Идентификаторы клиентов, секреты клиента, токены доступа? Все это казалось излишним для отображения собственного публичного фида Instagram. Поиск также мало помог — я нашел в основном ужасные сообщения о том, что Instagram закрывает общедоступный доступ к API (это правда, но доступ, который нам нужен, должен быть доступен до 2020 года, поэтому: вперед!).

Однако я столкнулся с одним примером приложения и увидел, что вызов Instagram не может быть проще:

let response = await fetch('https://api.instagram.com/v1/users/self/media/recent/?access_token=' + this.access_token )

Получив свой токен доступа и успешно загрузив свой фид, создание простой галереи было неожиданно быстрым благодаря Vue.js и CSS Grid.

Я надеюсь, что эта статья:

Поможет всем, кто хочет создать простой показ своего собственного фида Instagram

предоставит реальный пример Vue для начинающих с Vue

придаст легкости и мощности CSS Grid для построения макетов

Вот еще один пример того, что мы строим: мои Instagrams на моем сайте.

Получение токена доступа

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

Настройка оболочки страницы

В моем случае галерея собиралась сидеть на простой веб-странице, а не как часть веб-приложения. Это одна вещь, которая мне очень нравится в Vue: как с jQuery, вы можете просто занести ее на свою страницу и использовать по мере необходимости. Он не должен менять способ создания вашего сайта или страницы. Наша галерея Instagram будет довольно самодостаточной, помимо двух внешних ресурсов Javascript и, конечно же, вызова API Instagram. Вот оболочка страницы:

<!DOCTYPE html>
<html>
<head> <title>Instagram Gallery</title> <script src="https://unpkg.com/vue@2.5.16/dist/vue.min.js"></script> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <style type="text/css"> </style> </head>
<body> <div id="app"> </div> <script> </script> </body>
</html>

Мы предлагаем версию Vue.js, а также Axios.js, которая является предпочтительной библиотекой для создания HTTP-запросов из браузера в Vue. Вы можете использовать собственный API-интерфейс fetch () или vue-resource или что-то подходящее вам. Если вы уже загружаете jQuery на странице по другим причинам, вы можете даже использовать функцию $.ajax().

Затем у нас есть места для наших стилей, немного html и щепотка Javascript.

Код Vue

Давайте будем смелыми и сначала напишем наш Javascript:

var app = new Vue({ el: '#app', data: { access_token: "your access token here", url: "https://api.instagram.com/v1/users/self/media/recent/", username: "", grams: [], next_url: "", error: false }, computed: { instapage() { return 'https://www.instagram.com/' + this.username } }, methods: { getGrams() { axios.get(this.url + "?access_token=" + this.access_token) .then(({data}) => { this.grams = data.data this.username = data.data[0].user.username this.next_url = data.pagination.next_url }) .catch(function (error) { console.log(error) this.error = true }); }, getMoreGrams(){ axios.get(this.next_url) .then(({data}) => { this.grams = this.grams.concat(data.data) this.next_url = data.pagination.next_url }) .catch(function (error) { console.log(error) this.error = true }); } }, created() { this.getGrams(); }
})

Мы создаем новый экземпляр Vue и сначала говорим Vue, какой элемент для управления, с el: ‘#app’. Затем мы установили некоторые данные для Vue, чтобы отслеживать:

data: { access_token: "your access token here", url: "https://api.instagram.com/v1/users/self/media/recent/", username: "", grams: [], next_url: "", error: false
},

Значения url и access_token не изменятся (подключите токен доступа, который вы получили выше). Другие будут обновлены позже в нашем коде. У нас также есть одно вычислимое свойство:

computed: { instapage() { return 'https://www.instagram.com/' + this.username }
},

Значение instapage — это только URL-адрес страницы пользователя на Instagram. Да, вы уже знаете, какое username будет для вашей собственной галереи, поэтому наличие этого и instapage качестве динамических свойств немного глупо, но демонстрирует использование вычисленных свойств. И, имея меньше жестко закодированных значений, код становится немного более универсальным и более легким для повторного использования в будущих проектах.

Затем у нас есть сердце нашего маленького приложения, метод getGrams():

methods: { getGrams() { axios.get(this.url + "?access_token=" + this.access_token) .then(({data}) => { this.grams = data.data this.username = data.data[0].user.username this.next_url = data.pagination.next_url }) .catch(function (error) { console.log(error) this.error = true }); },
...
}

Мы используем Axios для вызова URL Instagram с добавлением access_token. В случае успеха мы обновляем наши свойства data. Это важный сдвиг в мышлении, который вы должны сделать между jQuery и Vue: с Vue все, о чем вы беспокоитесь, это данные. Больше элементов поиска, создания элементов, добавляющих элементов — код Javascript, который вы пишете, управляет и обновляет данные, на которых основано ваше приложение, и вы позволяете Vue f * ck с DOM.

(Замечание: несколько смутно, Axios возвращает объект response с свойством data, а API-интерфейс Instagram также имеет свойство data, которое содержит массив наших сообщений в Instagram. Следовательно, свойства вложенных data.)

Теперь нам нужно какое-то событие, чтобы сделать вызов метода getGrams(). Те, кто знаком с jQuery, используют для переноса кода в $(document).ready() или один из его эквивалентов. В нашем случае мы хотим назвать наш метод не тогда, когда документ готов, но когда экземпляр Vue готов, и для этого мы можем использовать один из хуков жизненного цикла Vue:

created() { this.getGrams();
}

Таким образом, как только экземпляр был «создан» Vue (наблюдение данных, вычисленные свойства, методы, обратные вызовы watch / event, все были установлены), вызовите наш getGrams(), который извлекает данные Instagram.

В нашем экземпляре Vue есть второй метод getMoreGrams(). Наряду с нашим массивом сообщений API Instagram возвращает next_url мы можем использовать для получения следующей партии сообщений, таким образом:

getMoreGrams(){ axios.get(this.next_url) .then(({data}) => { this.grams = this.grams.concat(data.data) this.next_url = data.pagination.next_url }) .catch(function (error) { console.log(error) this.error = true }); }

Как только эта новая партия сообщений вернется, мы просто добавим ее в наш массив grams, а Vue позаботится об остальном! Мы предоставим кнопку, которую пользователи могут щелкнуть, чтобы вызвать этот метод (в качестве альтернативы вы можете настроить ситуацию «бесконечной прокрутки», но я их ненавижу).

Для каждого из этих вызовов API мы выполняем некоторую очень основную обработку ошибок, которая будет отображать сообщение, если вызов завершился неудачно, установив для свойства реактивной error значение true.

Тело приложения Vue

Затем мы напишем наш код HTML / Vue:

<div id="app"> <h1><a :href="instapage">@{{ username }} on instagram</a></h1> <template v-if="grams.length > 0"> <div v-for="(gram, index) in grams"> <a :href="gram.link"> <img :src="gram.images.standard_resolution.url" :alt="gram.text" /> </a> </div> </template> <div v-else class="loading"></div> <div v-if="error" class="error">Sorry, the Instagrams couldn't be fetched.</div> <button @click="getMoreGrams">Load More</button>
</div>

Здесь у нас есть один контейнер div с идентификатором #app (который может радостно сидеть рядом с другими элементами HTML — ваш главный навигатор, футер и т. д.).

После простого заголовка с нашим именем пользователя мы хотим, чтобы divs содержащие каждую ссылку и изображение, были прямыми дочерними элементами нашей сетки CSS. Для этого мы используем элемент template как невидимую оболочку. Мы можем разместить здесь условие v-if, так что разметка внутри будет выводиться только в том случае, если у нас есть Instagrams для отображения:

<template v-if="grams.length > 0">

Если мы это сделаем, мы прокручиваем каждый и выводим изображение, заключенное в ссылку, используя данные, которые мы вернули с Instagram:

<div v-for="(gram, index) in grams"> <a :href="gram.link"> <img :src="gram.images.standard_resolution.url" :alt="gram.text" /> </a>
</div>

Пока нам нечего показать, мы можем показать простой графический загрузчик:

<div v-else class="loading"></div>

И если вызов Instagram терпит неудачу, мы можем сказать, что мы сожалеем:

<div v-if="error" class="error">Sorry, the Instagrams couldn't be fetched.</div>

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

<button @:click="getMoreGrams">Load More</button>

(@ является сокращением для v-on.)

Макет с CSS Grid

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

:root{ --color: #95e9ef; --background: #1f1f1f; --spacing: 1rem; --speed: 1700ms; --fontsize: 2rem; }
body{ margin: 0; padding: var(--spacing); font-family: Karbon, Helvetica, sans-serif; color: var(--color); background: var(--background);
}
#app{ display: grid; grid-gap: var(--spacing); grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); min-height: calc(100vh - var(--spacing)*2);
}
h1{ align-self: start;
}
h1, button{ margin: 0; padding: 0; grid-column: 1 / -1; font-size: var(--fontsize); line-height: 1.2; font-weight: 300; border: 4px solid var(--color); border-width: 4px 0;
}
img{ max-width: 100%; display: block;
}
button{ border-radius: 0; color: var(--color); background: transparent; grid-column: 1 / -1; outline: none; cursor: pointer; align-self: end;
}
a{ color: inherit; text-decoration: none;
}
.error{ grid-column: 1 / -1; justify-self: center;
}
.loading{ width: calc(var(--spacing)*3); height: calc(var(--spacing)*3); grid-column: 1 / -1; justify-self: center; align-self: center; background: var(--color); animation: load var(--speed) infinite ease-in-out; transform: rotate(0);
}
@keyframes load{ 100%{ transform: rotate(360deg); }
}

Сначала мы помещаем множество наших числовых значений в пользовательские свойства CSS в :root элементе (в нашем случае — в элементе html). Это удобно в трех вариантах:

Вы можете легко «переименовать» галерею для других сайтов.

Вы можете легко сохранять значения, без препроцессора или множественного поиска / замены.

В инструментах dev все интересные свойства, которые нужно играть, находятся в одном месте (элемент html), не переходя к объявлениям по отдельным элементам:

Затем мы создаем нашу сетку на #app:

#app{ display: grid; grid-gap: var(--spacing); grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); min-height: calc(100vh - var(--spacing)*2);
}

Мы даем нашей сетке некоторый интервал и устанавливаем столбцы с минимальной шириной 320px и максимальной шириной 1fr, что означает 1 часть доступного свободного места. Вы можете думать о fr как о «частях» в рецепте коктейля, например:

 grid-template-columns: 3fr 2fr 1fr; 

будет похож на рецепт, который требует 3 коньяка, 2 части три раза и 1 часть свежего лимонного сока. Это не говорит вам ничего об объеме коктейля, который вы сделаете, какая пропорция ингредиентов должна быть относительно друг друга и целого.

С repeat и auto-fill мы сообщаем браузеру повторять наш столбец с гибким размером столько раз, сколько поместится в #app div (что в нашем случае составляет 100% окна браузера). Вы заметите, что это делает нашу сетку полностью отзывчивой, без единого медиа-запроса!

Остальная часть CSS довольно проста. Одна из хороших сокращений, используемых в нескольких местах:

 grid-column: 1 / -1; 

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

 grid-column-start: 1; grid-column-end: -1; 

Когда используется отрицательное целое число, линии сетки будут подсчитываться с конца сетки, так что это говорит «начинать с первой линии сетки и заканчивать на последней линии сетки» независимо от того, сколько линий сетки есть.

Заключение

См. полный код на Gist.

Это супер-быстрый запуск в простой галерее Instagram, которая демонстрирует простоту использования и мощь Vue.js и CSS Grid.

Есть много улучшений и дополнительных функций, которые вы могли бы включить здесь: увлекательный стиль (Polaroid?); отображение дополнительных данных, таких как симпатии, титры и теги; более надежная обработка ошибок и резервные копии для старых браузеров.

Автор: Nora Brown

Источник: https://itnext.io/

Редакция: Команда webformyself.