От автора: если вы хоть раз пользовались интернет-магазинами типа eBay или Amazon, вы должны были использовать функцию превью. Она показывает вам изображения или видео о товаре, чтобы вы знали, что ожидать перед покупкой. В этой статье мы узнаем, как создать одностраничное приложение для превью типа Amazon с помощью Vue.js.
Мы создадим не точную копию сайта Amazon, но на нашем сайте будет превью характеристик товара.
Зависимости
Чтобы создать приложение будем использовать Node сервер для back end и Vue.js для front end. Прежде чем перейти к делу, необходимо установить на свою машину следующее:
Node
Node Package Manager(npm)
Создание front end
Для front end будем использовать Vue.js. Это прогрессивный JS фреймворк – быстрый и легкий в использовании.
Установка Vue.js
Необходимо установить Vue.js на свои машину. Подтвердить установку можно с помощью команды:
1 |
vue --version |
Если в ответ вернется номер версии, Vue.js установлен. Если нет, рекомендую установить Vue CLI с помощью команды:
1 |
npm install --global vue-cli |
Для создания frontend сервера запустите:
1 2 |
mkdir preview-app vue init webpack frontend |
Будет создан проект-пример Vue, который мы уже будем настраивать.
Установка модулей Node
Для отправки get запросов из одного из компонентов Vue.js будем использовать axios. Установите его с помощью следующей команды в папке frontend:
1 2 |
cd frontend npm install axios |
Создание компонента Listing
Компонент Listing показывает все товары в магазине и добавляет ссылку на просмотр товара. Чтобы создать компонент Listing, запустите следующую команду:
1 |
touch Listing.vue |
В Listing.vue сначала необходимо импортировать модуль axios:
1 2 3 |
<script> import axios from 'axios' //... |
Теперь с помощью этого модуля получаем список товаров:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//... export default { name: 'Listing', data () { return { products : [] } }, mounted : function(){ axios.get('//localhost:3128/products'). then( result => { console.log( result ); this.products = result.data; }) } } </script> |
В коде выше можно заметить, что после того, как мы смонтировали компонент, мы посылаем запрос на back end сервер и получаем доступные товары, записывая их в product data компонента.
Шаблон для компонента:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<template> <div class="listing container"> <div class="title" style="margin-bottom:40px;"> <h1>Products on Sale</h1> </div> <div class="row"> <div class="col-sm-2"> <h2>#</h2> </div> <div class="col-sm-8"> <h2>PRODUCT NAME</h2> </div> <div class="col-sm-2"> <h2>GO TO</h2> </div> </div> <template v-for="product in products"> <div class="row" style="margin-bottom:20px;"> <div class="col-sm-2" > <p>{{ product.id }}</p> </div> <div class="col-sm-8"> <p>{{ product.name }}</p> </div> <div class="col-sm-2"> <router-link :to="{path: '/product/'+product.id }">View Product</router-link> </div> </div> </template> </div> </template> |
В шаблоне сверху мы делаем list товаров в виде блоков div и добавляем кнопку, которая ведет вас на саму страницу одного товара.
Создание компонента Preview
Компонент Preview показывает данные и изображения выбранного товара с предыдущей страницы. После создания компонента мы посылаем get запрос на back end сервер и получаем все данные для определенного id, после чего показываем медиа в форме carousel на правой части экрана.
Создайте Preview.v
ue с помощью команды:
1 |
touch Preview.vue |
В файле Vue.js сперва необходимо импортировать модуль axios:
1 2 3 |
<script> import axios from 'axios' //... |
Теперь можно создать компонент:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
//... export default { name: 'Preview', data () { return { media :[], product_name : "", product_desc : "", product_price : "" } }, mounted : function(){ // now we get all the related infomation for the particular product id axios.get(`//localhost:3128/getProductInfo/${this.$route.params.id}`) .then( res => { this.media = res.data.media; this.product_name = res.data.product_name; this.product_desc = res.data.product_desc; this.product_price = res.data.product_price; }) }, methods : { initializePlayer : function(){ console.log('here') var cld = cloudinary.Cloudinary.new({ cloud_name: "og-tech", secure: true}); var demoplayer = cld.videoPlayer('video-player'); } } </script> |
После post запроса модель обновляется данными, которые вернулись в виде JSON ответа с back end. Шаблон представления:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
<template> <div class="preview"> <div class="row"> <div class="col-sm-6"> <!-- this part will contain the product info --> <h1> {{ product_name }} </h1> <div> <p> {{ product_desc }} </p> <p> Price : ${{ product_price }} </p> </div> </div> <div class="col-sm-6"> <!-- this part will contain the images --> <div id="demo" class="carousel slide" data-ride="carousel"> <!-- Indicators --> <ul class="carousel-indicators"> <template v-for="single_media in media"> <template v-if="single_media.id == 0"> <li data-target="#demo" v-bind:data-slide-to="single_media.id" class="active"></li> </template> <template v-else> <li data-target="#demo" v-bind:data-slide-to="single_media.id"></li> </template> </template> <!-- <li data-target="#demo" data-slide-to="0" class="active"></li> <li data-target="#demo" data-slide-to="2"></li> --> </ul> <!-- The slideshow --> <div class="carousel-inner"> <template v-for="single_media in media"> <template v-if="single_media.id == 0"> <div class="carousel-item active"> <template v-if="single_media.type == 'image'"> <img class="img-responsive single-image" v-bind:src="single_media.url"/> </template> <template v-else> <video id="video-player" controls class="single-image cld-video-player cld-video-player-skin-dark" v-bind:data-cld-source="single_media.url" > </video> </template> </div> </template> <template v-else> <div class="carousel-item"> <template v-if="single_media.type == 'image'"> <img class="img-responsive single-image" v-bind:src="single_media.url"/> </template> <template v-else> <video id="video-player" controls class="single-image cld-video-player cld-video-player-skin-dark" v-bind:data-cld-source="single_media.url" > </video> </template> </div> </template> </template> </div> <!-- Left and right controls --> <a class="carobbusel-control-prev" href="#demo" data-slide="prev"> <span class="carousel-control-prev-icon"></span> </a> <a class="carousel-control-next" href="#demo" data-slide="next" v-on:click="initializePlayer()"> <span class="carousel-control-next-icon"></span> </a> </div> </div> </div> </div> </template> |
В шаблоне выше мы хотим показать медиа для определенного товара. Взгляните на то, когда мы создаем компонент – мы посылаем запрос на back end и далее посылаем ответ в компонент Vue.
Нам нужно знать, какое медиа отображается, изображение или видео. Проверим это в шаблоне:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//.. <template v-if="single_media.type == 'image'"> <img class="img-responsive single-image" v-bind:src="single_media.url"/> </template> <template v-else> <video id="video-player" controls class="single-image cld-video-player cld-video-player-skin-dark" v-bind:data-cld-source="single_media.url" > </video> </template> //.. |
Если медиа имеет type of image, мы показываем изображение в карусели. Но если type видео, мы показываем видео с помощью Cloudinary VIdeo Player. Чтобы инициализировать видео плеер, добавим v-on:click событие на кнопку >. После клика по кнопке инициализируется плеер с видео.
PS: видео плеер Cloudinary проигрывает видео по тегам и плейлистам. Подробнее читайте здесь. У представления превью есть свои стили:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<style scoped> h1, h2 { font-weight: normal; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } .carousel-inner{ height : 500px; } .carousel-item{ height : 100%; } .single-image{ width : 100%; height: 100%; object-fit : fill; } #demo{ margin-left: 30px; margin-right: 30px; } </style> |
Связывание компонентов
Для перехода от одного компонента к другому в Vue есть так называемый vue-router. Откройте файл frontend/src/router/index.js и отредактируйте его следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
// frontent/src/router/index.js import Vue from 'vue' import Router from 'vue-router' import HelloWorld from '@/components/HelloWorld' import Listing from '@/components/Listing' import Preview from '@/components/Preview' Vue.use(Router) export default new Router({ routes: [ { path: '/', name: 'Listing', component: Listing }, { path: '/product/:id', name: 'Product', component: Preview } ] }) |
Код сверху задает доступные роуты приложения. Ранее в компонентах мы использовали <router-link> для перехода с компонента Listing в компонент Preview. Этот файл обрабатывает то, что вы получаете. При создании роутеров можно указать намного больше опций.
Создание back end
Чтобы создать back end, необходимо сменить папку на корневую и установить модули Node:
1 2 |
cd preview-app npm install cors express body-parser dotenv request connect-multiparty cloudinary |
Вы успешно установили все модули, необходимые для создания проекта.
Создание файла server.js
Теперь необходимо создать файл, который будет хранить инструкции для работы нашего сервера в папке video-suggestion,
1 |
touch server.js |
Это будет файл запуска, на который вы будете ссылаться во время работы сервера в файле server.js. Вам необходимо импортировать модули node.
1 2 3 4 5 6 7 8 9 |
require('dotenv').config() const cors = require('cors') const express = require('express') const bodyParser = require('body-parser') const multipart = require('connect-multiparty') const request = require('request') const cloudinary = require('cloudinary') //... |
После импорта node модулей их можно сводобно использовать по всему скрипту.
Создание экспресс приложения
Создадим объект экспресс приложения, добавив в server.js строку:
1 2 3 4 5 |
//... const app = express() //... |
Загрузка промежуточного кода
Загружаем промежуточной код в server.js, добавив следующий код:
1 2 3 4 5 6 7 8 |
//... app.use(cors()) app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); const multipartMiddleware = multipart(); //... |
Здесь мы указали, что приложение будет использовать cors. Мы также указали приложению парсить запросы в JSON формат.
Настройка клиента Cloudinary
Необходимо настроить клиент cloudinary с помощью CLOUD_NAME, API_KEY и API_SECRET.
1 2 3 4 5 6 7 8 9 |
//... cloudinary.config({ cloud_name: 'CLOUDINARY_CLOUD_NAME', api_key: 'CLOUDINARY_API_KEY', api_secret: 'CLOUDINARY_API_SECRET' }); //... |
Мы успешно настроили клиент Cloudinary.
Создание роутов приложения
Наш back end сервер крайне прост. Это экспресс веб-сервер с двумя главными роутами:
/products – перечисляет все товары, доступные для продажи.
/getProductInfo – возвращает данные для выбранного товара.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
//... app.get('/products', multipartMiddleware, function(req, res){ return res.json([ {id: '1', name: 'UltraLight Mechanical Keyboard'}, {id: '121', name: 'IPhone X'}, {id: '23', name: 'Tesla S'}, {id: '42', name: 'Work Shoes'} ]); }); app.get('/getProductInfo/:id', multipartMiddleware, function(req, res){ console.log( req.params.id ); return res.json({ media: [ { id: '0', type: 'image', url: '//static.pexels.com/photos/265631/pexels-photo-265631.jpeg' }, [...] { id: '3', type: 'video', url: '//res.cloudinary.com/og-tech/video/upload/s--ZWPqo282--/v1514966645/sea_turtle-short_z1pr4o.mp4' }, ], product_name: 'Ultra Thin Mechanical Keyboard', product_desc: 'This keyboard gives you the clack to your click', product_price: '200' }) }); //... |
В коде сверху роуты возвращают ответы в JSON формате для дальнейшего использования на front end. Возможно, вы заметили, что много (все) данных, возвращенных пользователю, статичны. В реальном приложении вы будете возвращать пользователю динамичные данные.
Роут /productInfo принимает id товара. С его помощью вы будете определять, какие данные хранить, вместо того, чтобы просто возвращать статичные json данные. Другими словами, вы можете сделать дальнейший запрос в базу данных или облачное хранилище для получения информации и возврата данных в формате, используемом сверху.
Настройка порта приложения
Задаем порт, который будет слушать наше приложение:
1 2 3 4 5 6 7 |
[...] let port = 3128 || process.env.PORT; app.listen(port, function () { console.log('App listening on port ' + port + '!'); }); |
Заключение
В этой статье мы узнали, как использовать изображения и видео Cloudinary с Vue.js для создания приложения превью типа Amazon для товаров.
Автор: Chris Nwamba
Источник: //scotch.io/
Редакция: Команда webformyself.