Ранее мы реорганизовали наше приложение, чтобы оно было более гибким и DRY. В этой статье мы добавим 3 новых компонента на домашнюю страницу, которая в настоящее время пуста:
Начнем с компонента HeroSection.vue. Создадим файл с таким именем в каталоге компонентов. В нем будет следующее:
background-image: url('relative-or-external-path.jpg');
<template> <section class="hero" :style="{backgroundImage: heroImagePath()}"> <h1 class="hero-title">{{ title }}</h1> <p class="hero-subtitle">{{ subtitle }}</p> </section> </template> <script> export default { name: 'heroSection', props: { backgroundImage: String, title: String, subtitle: String, }, methods: { heroImagePath() { return 'url(' + require(`../assets/${this.backgroundImage}`) + ')'; } } } </script> <style lang="scss"> .hero { background-size: cover; background-repeat: no-repeat; background-position: center center; color: white; text-align: center; display: flex; flex-direction: column; justify-content: center; align-items: center; min-height: 600px; @media only screen and (min-width: 600px) and (max-width: 900px) { min-height: 400px; } @media only screen and (max-width: 599px) { min-height: 250px; } } .hero-title { font-size: 3rem; margin: 0; } .hero-subtitle { font-size: 1.3rem; } </style>
Теперь посетите Unsplash или Pixabay, и загрузите от туда бесплатную фотографию на ваш выбор в качестве фонового изображения. Сохраните его в assets как homepage-hero.jpg.
Затем перейдите в Home.vue и обновите его следующим образом:
<template> <div> <hero-section backgroundImage="homepage-hero.jpg" title="Welcome to Instaflickr" subtitle="A fake photo app"/> <div class="wrapper"> </div> </div> </template> <script> import HeroSection from '@/components/HeroSection'; export default { name: 'home', components: { HeroSection, } }; </script>
В нем мы импортируем и регистрируем компонент HeroSection. Затем мы добавляем его в шаблон, передавая необходимые реквизиты.
Теперь давайте создадим раздел на главной странице, чтобы показать три самые последние фотографии, которые были загружены на Flickr. Мы будем использовать метод flickr.photos.getRecent, который потребует наш api_key и так де принимает много дополнительных параметров, аналогичных методу flickr.photos.search, таких как extras, per_page и page. Он отлично подойдет к нашему вспомогательному методу flickr.js, который мы сделали в части 2. А так же мы воспользуемся нашим компонентом ImageCard для отображения получаемых изображений.
Создайте файл с именем RecentPhotos.vue внутри папки компонентов. В нем мы сделаем следующее:
Это будет наш стандартный подход/процесс для всех остальных вызовов API в этом проекте.
<template> <section class="content-section margin-y--6"> <h2 class="centered">Browse the Latest Uploads</h2> <ul class="image-card-grid"> <image-card v-for="image in mostRecentPhotos" :key="image.id" :image="image" /> </ul> </section> </template> <script> import flickr from '../flickr' import ImageCard from './ImageCard.vue' export default { name: 'recentPhotos', components: { ImageCard }, created() { this.fetchRecentPhotos() }, data() { return { recentPhotos: [], } }, computed: { mostRecentPhotos() { return this.recentPhotos.slice(0, 3) }, }, methods: { fetchRecentPhotos() { return flickr("photos.getRecent", { extras: "url_n, owner_name, description, date_taken, views", page: 1, per_page: 3, }) .then((response) => { this.recentPhotos = response.data.photos.photo }) .catch((error) => { console.log("Error occured: ", error) }) }, } } </script> <style> .centered { text-align: center; } .margin-y--6 { margin-top: 6rem; margin-bottom: 6rem; } </style>
Затем добавьте новый компонент в компонент Home.vue, импортировав и зарегистрировав его и, затем добавим тег в шаблон.
<template> <div> <hero-section backgroundImage="homepage-hero.jpg" title="Welcome to Instaflickr" subtitle="A fake photo app"/> <div class="wrapper"> <recent-photos /> </div> </div> </template> <script> import HeroSection from '@/components/HeroSection'; import RecentPhotos from '@/components/RecentPhotos'; export default { name: 'home', components: { HeroSection, RecentPhotos } }; </script>
Другой популярный способ поиска фотографий — по названию города или места. Давайте создадим интерактивный компонент, который позволяет пользователям просматривать фотографии из ограниченного списка «популярных» мест. Мы произвольно укажем места какие мы хотим видеть.
Создайте файл с именем PlacePhotos.vue внутри папки компонентов. Наш шаблон будет состоять из заголовка и список кнопок с названием мест. Каждая кнопка будет обновляет список из 3 фотографий с выбранного места; вторая строка — это loading который будет появляться во время выборки изображений. Внизу будет ссылка, по которой пользователь может щелкнуть, чтобы просмотреть другие фотографии этого места на странице SearchResults.
Разберем это еще раз и начнем с первой части, списка мест ul:
Теперь давайте посмотрим на вторую часть, image-card-grid u:
place_id: this.popularPlaces[this.selectedPlaceIndex].place_id
мы перемещаем первую часть в ее собственное вычисляемое свойство с именем selectedPlace , что позволяет нам написать так:
place_id: this.selectedPlace.place_id
Что гораздо более читабельно.
Наконец, давайте посмотрим на третью часть шаблона:
<template> <section class="content-section margin-y--6"> <h2 class="centered">Daydream by Place</h2> <ul class="place-list"> <li v-for="(place, index) in popularPlaces" :key="place.place_id" class="place-list__item"> <button @click="updateSelectedPlaceIndex(index)" class="place-list__item__button" :class="{'selected': index === selectedPlaceIndex}"> {{place.name}} </button> </li> </ul> <ul v-if="!loading" class="image-card-grid"> <image-card v-for="image in popularPlacePhotos" :key="image.id" :image="image" /> </ul> <ul v-else class="image-card-grid"> <image-card v-for="n in 3" :key="n" :loading="true" /> </ul> <p class="centered"> <router-link :to="{name: 'searchResults', params: { tag: selectedPlace.name }}" class="btn btn--dark-grey more-photos"> More Photos of {{selectedPlace.name}} </router-link> </p> </section> </template> <script> import flickr from '../flickr' import ImageCard from './ImageCard.vue' export default { name: 'daydreamByPlace', components: { ImageCard }, created() { this.fetchPlacePhotos() }, watch: { selectedPlace() { this.fetchPlacePhotos() } }, data() { return { loading: true, placePhotos: [], selectedPlaceIndex: 0, popularPlaces: [ { name: 'Agra', place_id: 'S4OOvxtTULO18fQG' }, { name: 'Bali', place_id: 'lm4_wrhTUb4oe5pO' }, { name: 'Rio de Janeiro', place_id: 'mAqmHW5VV78OT5o' }, { name: 'Paris', place_id: 'EsIQUYZXU79_kEA' }, { name: 'Tokyo', place_id: 'FRthiQZQU7uKHvmP' }, { name: 'Tolanaro', place_id: 'qdHKy7VQUbxPQVBX' } ] } }, computed: { selectedPlace() { return this.popularPlaces[this.selectedPlaceIndex] }, popularPlacePhotos() { return this.placePhotos.slice(0, 3) }, }, methods: { fetchPlacePhotos() { this.loading = true flickr("photos.search", { place_id: this.selectedPlace.place_id, extras: "url_n, owner_name, description, date_taken, views", page: 1, per_page: 3, }).then((response) => { this.placePhotos = response.data.photos.photo this.loading = false }) .catch((error) => { console.log("Error occured: ", error) }) }, updateSelectedPlaceIndex(index) { this.selectedPlaceIndex = index; }, } } </script> <style lang="scss"> .btn--dark-grey { background: #2c3e50; color: white; text-decoration: none; } .place-list { list-style: none; padding: 0; margin: 0; width: 100%; display: flex; align-items: center; justify-content: center; flex-wrap: wrap; } .place-list__item { margin: 0 .5rem; } .place-list__item__button { background: transparent; font-size: 1rem; border: 0; outline: 0; cursor: pointer; border-radius: 3px; padding: .5rem .75rem; &.selected { background: #F0F0F0; } transition: all .3s ease; &:hover { color: #42b983; } } </style>
Единственными оставшимися шагами теперь являются импорт и регистрация PlacePhotos.vue в Home.vue и добавление его в шаблон:
<template> <div> <hero-section backgroundImage="homepage-hero.jpg" title="Welcome to Instaflickr" subtitle="A fake photo app"/> <div class="wrapper"> <recent-photos /> <place-photos /> </div> </div> </template> <script> import HeroSection from '@/components/HeroSection'; import RecentPhotos from '@/components/RecentPhotos'; import PlacePhotos from '@/components/PlacePhotos'; export default { name: 'home', components: { HeroSection, RecentPhotos, PlacePhotos } }; </script>
И вот наконец мы все сделали! Три новых компонента и еще два места, где мы используем Flickr API. Спасибо за чтение и до встречи!
Оригинал: Simple Photo App with Vue.js, Axios, and Flickr API — Part 3
Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…
Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…
Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…
Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…
Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…
Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…