vuex, router로 영화 앱 만들기 예제
// index.js
export default new Vuex.Store({
state: {
movies: {
dunkirk: {
id: 'dunkirk',
title: 'Dunkirk',
subtitle: 'Dunkirk',
description: `Miraculous evacuation of Allied soldiers from Belgium, Britain, Canada, and France, who were cut off and surrounded by the German army from the beaches and harbor of Dunkirk, France, during the Battle of France in World War II.`,
largeImgSrc: `url('https://image.tmdb.org/t/p/w780/fudEG1VUWuOqleXv6NwCExK0VLy.jpg')`,
smallImgSrc: 'https://image.tmdb.org/t/p/w185/fudEG1VUWuOqleXv6NwCExK0VLy.jpg',
releaseDate: 'July 21 2017',
duration: '1hr 46min',
genre: 'Action, Drama, History',
trailerPath: 'https://www.youtube.com/embed/F-eMt3SrfFU',
favorite: false
},
...
먼저 영화 정보를 vuex에 담아주었습니다.
// App.vue
<template>
<div id="app">
<MovieList />
</div>
</template>
<script>
import MovieList from "@/components/MovieList";
export default {
data() {
return {};
},
components: {
MovieList
}
};
</script>
영화 정보들을 불러오는 리스트를 만들기 위해
MovieList 컴포넌트를 만들겠습니다.
// MovieList.vue
<template>
<div>
<div v-for="(movie, index) in movies" :key="index" class="movie_choice">
<img :src="`${movie.smallImgSrc}`" alt />
</div>
</div>
</template>
<script>
import { mapState } from "vuex";
export default {
data() {
return {};
},
computed: {
...mapState(["movies"])
}
};
</script>
mapState로 데이터들을 가져오고 v-for를 이용해 리스트를 만들어줬습니다.
라우터를 이용해 인트로 페이지, 영화 페이지, 예고편 페이지를 만들겠습니다.
// Intro.vue
<template>
<div>
<h1 class="title">VUECHA PLAY</h1>
<p>Select a movie</p>
</div>
</template>
인트로 페이지를 만들고 이 페이지를 첫 화면으로 만들기 위해 라우터 세팅을 해줍니다.
path를 '/' 로 설정해 첫 페이지에 보여지게 합니다.
// index.js
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
const Intro = () => import(/* webpackChunkName: "intro" */ '../views/Intro.vue');
const routes = [
{
path: '/',
name: 'Intro',
component: Intro
},
];
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
});
export default router;
App.vue 에 router-view를 만들어줬습니다.
// App.vue
<template>
<div id="app">
<router-view />
<MovieList />
</div>
</template>
이제 라우터로 영화 경로로 넘어가지도록 하겠습니다.
MovieList.vue를 수정하겠습니다.
// MovieList.vue
<template>
<div class="colum">
<div v-for="(movie, index) in movies" :key="index" class="movie_choice">
<router-link :to="`/${movie.id}`" tag="li">
<img :src="`${movie.smallImgSrc}`" alt />
</router-link>
</div>
</div>
</template>
그리고 라우터의 경로를 동적으로 받도록 하겠습니다.
// index.js
const Intro = () => import(/* webpackChunkName: "intro" */ '../views/Intro.vue');
const Movie = () => import(/* webpackChunkName: "about" */ '../views/Movie.vue');
const routes = [
{
path: '/',
name: 'Intro',
component: Intro
},
{
path: '/:id',
name: 'Movie',
component: Movie
},
];
라우터의 파라미터로 id를 받으면 Movie.vue를 호출하도록 했습니다.
이제 Movie.vue를 만들겠습니다.
// Movie.vue
<template>
<h1>{{ selectedMovie.title }}</h1>
</template>
<script>
export default {
data() {
return {
selectedMovie: this.$store.state.movies[this.$route.params.id]
};
},
watch: {
$route() {
this.selectMovie();
}
},
methods: {
selectMovie() {
this.$set(
this.$data,
"selectedMovie",
this.$store.state.movies[this.$route.params.id]
);
}
}
};
</script>
selectedMovie의 속성에 파라미터로 받은 id를 담아주고
watch로 라우터가 변경될 때마다 methods의 selectMovie로 selectedMovie를 업데이트 해줍니다.
잘 작동하는 걸 확인하고 이제 영화 정보들을 넣어줍니다.
// Movie.vue
<template>
<div
:style="{ 'background-image': selectedMovie.largeImgSrc }"
>
<header class="nav">
<router-link to="/" class="btn_home">Home</router-link>
<strong>VUECHA PLAY</strong>
</header>
<div class="desc">
<h1>{{ selectedMovie.title }}</h1>
<ul class="sub_title">
<li>{{ selectedMovie.duration }} /</li>
<li>{{ selectedMovie.genre }} /</li>
<li>{{ selectedMovie.releaseDate }}</li>
</ul>
<p>{{ selectedMovie.description }}</p>
</div>
<div class="link">
<router-link
:to="{path: '/' + $route.params.id + '/trailer' }"
tag="button"
class="btn_play"
>Play</router-link>
</div>
</div>
</template>
영화 재생버튼을 누르면 '/' + $route.params.id + '/trailer' 이러한
경로로 현재 경로를 확장하여 영화 예고편 페이지를 만들어 줍니다.
라우터에 경로를 추가해줍니다.
const Intro = () => import(/* webpackChunkName: "intro" */ '../views/Intro.vue');
const Movie = () => import(/* webpackChunkName: "about" */ '../views/Movie.vue');
const MovieTrailer = () => import(/* webpackChunkName: "trailer" */ '../components/MovieTrailer.vue');
const routes = [
{
path: '/',
name: 'Intro',
component: Intro
},
{
path: '/:id',
name: 'Movie',
component: Movie
},
{
path: '/:id/trailer',
name: 'Trailer',
component: MovieTrailer
}
];
그리고 MovieTrailer 컴포넌트를 추가해줍니다.
// MovieTrailer.vue
<template>
<div>
<iframe frameborder="0" allowfullscreen :src="trailerUrlPath"></iframe>
</div>
</template>
<script>
export default {
data() {
return {
trailerUrlPath: this.$store.state.movies[this.$route.params.id]
.trailerPath
};
}
};
</script>
잘 나오는군요
마지막으로 즐겨찾기 버튼을 만들겠습니다.
Movie.vue파일을 수정합니다.
// Movie.vue
<template>
<div
:style="{ 'background-image': selectedMovie.largeImgSrc }"
:class="[{ 'favorite' : selectedMovie.favorite }, 'wrap']"
>
<header class="nav">
<router-link to="/" class="btn_home">Home</router-link>
<strong>VUECHA PLAY</strong>
</header>
<div class="desc">
<h1>{{ selectedMovie.title }}</h1>
<ul class="sub_title">
<li>{{ selectedMovie.duration }} /</li>
<li>{{ selectedMovie.genre }} /</li>
<li>{{ selectedMovie.releaseDate }}</li>
</ul>
<p>{{ selectedMovie.description }}</p>
</div>
<div class="link">
<router-link
:to="{path: '/' + $route.params.id + '/trailer' }"
tag="button"
class="btn_play"
>Play</router-link>
<button class="btn_favorite" @click="addFavorite(selectedMovie)">
<span v-show="!selectedMovie.favorite">Add to</span>
<span v-show="selectedMovie.favorite">Remove from</span>
Favorite
</button>
</div>
</div>
</template>
<script>
export default {
methods: {
addFavorite(selectedMovie) {
console.log(selectedMovie);
this.$store.state.movies[this.$route.params.id].favorite = !this.$store
.state.movies[this.$route.params.id].favorite;
}
}
};
</script>
완성!
출처 : https://hackernoon.com/building-a-movie-app-interface-with-vue-js-cdc8aeb5db0b