๐ŸŽฌ Vue Project

ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ

๐Ÿ™Žโ€โ™‚๏ธ๐Ÿ™โ€โ™€๏ธ ํ”„๋กœ์ ํŠธ ๋ฉค๋ฒ„

  • ํ™ฉ์ˆ˜๋ฏผ
  • ์‹ ์˜์ฐฌ
  • ์‹ ์ฑ„๋ฆฐ

๐Ÿ’ป ๊ธฐ์ˆ  ์Šคํƒ

  • Framework ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
    Vue.Js Bootstrap
    Axios

๐Ÿ“‚ ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ

image-20200603171819446


๐Ÿ“Œ ๊ธฐ๋Šฅ

  • ์˜ํ™” ๊ฐ€์ ธ์˜ค๊ธฐ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด, ์˜ํ™”๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
    • ๊ฐœ๋ณ„ ์˜ํ™”๋ฅผ ํด๋ฆญํ–ˆ์„ ๋•Œ, ์ƒ์„ธ ์ค„๊ฑฐ๋ฆฌ์™€ ํฌ์Šคํ„ฐ ์‚ฌ์ง„์ด ๋ณด์—ฌ์ง‘๋‹ˆ๋‹ค.
  • ์˜ํ™” ์ด๋ฆ„ ๊ฒ€์ƒ‰ ์‹œ, ๊ฒ€์ƒ‰ํ•œ ์˜ํ™”์˜ ์˜ˆ๊ณ ํŽธ๋“ค์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.
    • ๊ฒ€์ƒ‰์–ด๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ, ์˜ํ™” ์˜ˆ๊ณ ํŽธ์„ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

Discussion

  • App.vue์— MovieView.vue์— VideoView.vue๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ.
  • routing์˜ ํ•„์š”์„ฑ (2๊ฐœ๋งŒ ํ•„์š”) MovieView์™€ VideoView๋ฅผ ๋งŒ๋“ค๊ธฐ
  • Convention ๋งž์ถ”๊ธฐ
    • import ํ•  ๋•Œ '../components/MovieListItemModal.vue'
      • ๋์— ํ™•์žฅ์ž (vue) ๋„ฃ์„์ง€ ๋ง์ง€ ๊ฒฐ์ •

๊ตฌํ˜„ ๊ณผ์ •

โš™๏ธ ์ดˆ๊ธฐ ์„ค์ •

๋ผ์šฐํ„ฐ ์ถ”๊ฐ€

  • $ vue add router

์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ

  • ์‚ฌ์šฉํ•  ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ชจ๋‘ ์ƒ์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค. (MovieList.vue, MovieListItem.vue, MovieListItemModal.vue, VideoItem.vue, VideoItemDetail.vue, VideoSearch.vue)

ํด๋” ๊ตฌ์กฐ

  • ๋ฉ”์ธ ํŽ˜์ด์ง€์—์„œ ๋ณด์—ฌ์ค„ ๋‘ ์ปดํฌ๋„ŒํŠธ MovieView.vue์™€ VideoView.vue๋ฅผ ์ œ์™ธํ•˜๊ณ , ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋“ค์€ components ํด๋” ์•ˆ์— ๋„ฃ์—ˆ์Šต๋‹ˆ๋‹ค .
  • MovieView.vue์™€ VideoView.vue๋Š” views ํด๋” ์•ˆ์— ๋„ฃ์—ˆ์Šต๋‹ˆ๋‹ค.

router/index.js ์ถ”๊ฐ€

    1. index.js ํŒŒ์ผ์— MovieView.vue์™€ VideoView.vue๋ฅผ import ์‹œ์ผฐ์Šต๋‹ˆ๋‹ค.
    1. routes์— Movie์™€ Video์˜ path, name, component๋ฅผ ์„ค์ •ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

โš™๏ธ url
  • MovieView.vue๋Š” '/'๋กœ url์„ ์ƒ์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • VideoView.vue๋Š” '/video'๋กœ url์„ ์ƒ์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.

App.vue

navigation ์ถ”๊ฐ€

  • navigation์€ bootstrap์—์„œ ๊ฐ€์ ธ์™”์Šต๋‹ˆ๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  ๊ฐ ๋ฉ”๋‰ด๋ฅผ ํด๋ฆญํ–ˆ์„ ๋•Œ, <router-link to="/">Movie</router-link>์™€ ๊ฐ™์€ ํ˜•์‹์œผ๋กœ ํ™œ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.

Movie

MovieView.vue

Axios ์‚ฌ์šฉ
  • ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ Axios๋ฅผ ํ†ตํ•ด movies ๋ฐฐ์—ด์„ ๊ฐ€์ ธ์™”์Šต๋‹ˆ๋‹ค.
  • ์ด๋ฅผ data์— movies์— ์ €์žฅํ•˜์˜€์Šต๋‹ˆ๋‹ค.
methods: {
    onButtonClick() {
      axios.get('https://www.json-generator.com/api/json/get/ceNyuXZmwi?indent=2')
        .then(
          res => {
            this.movies = res.data
          })
        .catch(err => console.error(err));
    }
  }
v-bind ์‚ฌ์šฉ
  • Axios๋ฅผ ํ†ตํ•ด ๋ฐ›์•„์˜จ movies ๋ฐฐ์—ด์„ v-bind๋กœ MovieList.vue์— ๋ณด๋‚ด์ค๋‹ˆ๋‹ค.
<MovieList :movies="movies"/>

MovieList.vue

์ปดํฌ๋„ŒํŠธ ์„ค๋ช…
  • ์˜ํ™” ๋ฆฌ์ŠคํŠธ๋“ค์ด ๋“ค์–ด์˜ฌ ์˜์—ญ์ž…๋‹ˆ๋‹ค.

props ์‚ฌ์šฉ
  • MovieView.vue์—์„œ ๋„˜๊ธด movies๋ฅผ props์— ๋ฐ์ดํ„ฐ ํƒ€์ž…์„ ์ง€์ •ํ•ด ์ค€ ํ›„ ๋ฐ›์•„์™”์Šต๋‹ˆ๋‹ค.
import MovieListItem from './MovieListItem.vue'

export default {
  name : 'MovieList',
  components: {
    MovieListItem
  },
  props: {
    movies: Array,
  },
}
v-for๋ฅผ ํ†ตํ•œ MovieListItem.vue๋ฅผ ๋งŒ๋“ค๊ธฐ
  • v-for๋ฅผ ์ด์šฉํ•ด movies์˜ ๊ฐ์ฒด๋“ค์„ ํ•˜๋‚˜์”ฉ ๋Œ๋ฉด์„œ MovieListItem์œผ๋กœ ๋„˜๊ฒจ์ค๋‹ˆ๋‹ค.
<MovieListItem class="col-3" :movie = "movie" v-for="movie in movies" :key="movie.id"/>

MovieListItem.vue

์ปดํฌ๋„ŒํŠธ ์„ค๋ช…
  • ๊ฐœ๋ณ„ ์˜ํ™”๊ฐ€ ๋“ค์–ด์˜ฌ ์˜์—ญ์ž…๋‹ˆ๋‹ค. col-3์„ ์ด์šฉํ•ด row์˜ 4๋ถ„์˜ 1์„ ์ฐจ์ง€ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
props ์‚ฌ์šฉ
  • MovieListItem.vue์—์„œ๋Š” MovieList.vue์—์„œ v-bind๋กœ ๋„˜์–ด์˜จ movie๋ฅผ ๋ฐ›์•„์„œ, ํ•ด๋‹น ์˜ํ™”์˜ ์นด๋“œ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
    • <script> ๋‚ด๋ถ€์— MovieList.vue์—์„œ ๋„˜์–ด์˜จ movie ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›๊ธฐ ์œ„ํ•ด props๋ฅผ ์ด์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.
Bootstrap Card ์‚ฌ์šฉ
  • ์นด๋“œ๋Š” Bootstrap์— ์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ์ด์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.
v-bind ์‚ฌ์šฉ
  • ๋˜ํ•œ, MovieListItemModal.vue์— ํ•ด๋‹น ์˜ํ™”๋ฅผ ๋„˜๊ฒจ์ฃผ๊ธฐ ์œ„ํ•ด v-bind๋ฅผ ์ด์šฉํ•ด movie๋ฅผ ์‚ฌ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.
โ—๏ธ ์–ด๋ ค์› ๋˜ ์ 
  • ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ, ๋ชจ๋‹ฌ์„ ๋„์›Œ์•ผ ํ•˜๋Š”๋ฐ ๋ฒ„ํŠผ์˜ data-target๊ณผ ๋ชจ๋‹ฌ์˜ id๋ฅผ ํ†ต์ผ์‹œํ‚ค๋Š” ๋ถ€๋ถ„์ด ์–ด๋ ค์› ์Šต๋‹ˆ๋‹ค.
  • ํŠนํžˆ, data-target์˜ id๋ฅผ movie.id๋กœ ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค์ง€ ๊ณ ๋ฏผํ–ˆ์Šต๋‹ˆ๋‹ค.
โญ ํ•ด๊ฒฐ
  • <template>
    	<img :data-target="'#movie'+movie.id">
    </template>
    • concatenation์„ ํ†ตํ•ด #movie์™€ movie.id๋ฅผ ๊ฐ™์ด ๋”ํ•ด์„œ id๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

MovieListItemModal.vue

์ปดํฌ๋„ŒํŠธ ์„ค๋ช…
  • ๊ฐœ๋ณ„ ์˜ํ™”๋ฅผ ํด๋ฆญ ์‹œ, ๋ชจ๋‹ฌ์— ๋„์›Œ์ค„ ์ˆ˜ ์žˆ๋„๋ก ๋ชจ๋‹ฌ์„ ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.
Bootstrap Modal ์‚ฌ์šฉ
  • ๋ชจ๋‹ฌ์€ Bootstrap์— ์žˆ๋Š” Live Modal ์ฝ”๋“œ๋ฅผ ์ด์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.
props ์‚ฌ์šฉ
  • MovieListItem.vue์—์„œ ๋„˜๊ฒจ์ค€ movie ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›๊ธฐ ์œ„ํ•ด props๋ฅผ ์ด์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.
โ—๏ธ ์–ด๋ ค์› ๋˜ ์ 
  • ์ด๋ฏธ์ง€๋ฅผ ์•„๋ฌด๋Ÿฐ attribute ์—†์ด ์‚ฝ์ž…ํ–ˆ๋”๋‹ˆ, Modal ๋ฐ–์œผ๋กœ ์ด๋ฏธ์ง€๊ฐ€ ๋‚˜๊ฐ”์Šต๋‹ˆ๋‹ค.
โญ ํ•ด๊ฒฐ
  • ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๊ตฌ๊ธ€๋ง ํ•˜์˜€๊ณ , ๊ทธ ๊ฒฐ๊ณผ Bootstrap4์— img-fluid๋ผ๋Š” ํด๋ž˜์Šค๊ฐ€ ์žˆ๋‹ค๋Š” ์ ์„ ๋ฐฐ์› ์Šต๋‹ˆ๋‹ค.
  • img-fluid๋ฅผ ์ด์šฉํ•˜๋‹ˆ ๋ถ€๋ชจ์ธ Modal์˜ width์— ๋งž์ถฐ ์ด๋ฏธ์ง€ ๋„ˆ๋น„๊ฐ€ ์กฐ์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

Video

VideoView.vue

API ์‚ฌ์šฉ
  • VideoView.vue ์ปดํฌ๋„ŒํŠธ ํ•˜์œ„์—์„œ ๊ณตํ†ต์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” videos data์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

  • videos

    • youtube API์— axios ๋น„๋™๊ธฐ ํ†ต์‹  ๊ฒฐ๊ณผ๋กœ ๋ฐ›์•„์˜จ ๊ฐ’๋“ค์„ ์ €์žฅํ•˜๋Š” ๋ฐฐ์—ด์ž…๋‹ˆ๋‹ค.

VideoSearch.vue

์ปดํฌ๋„ŒํŠธ ์„ค๋ช…
  • ์‚ฌ์šฉ์ž๊ฐ€ ์˜ˆ๊ณ ํŽธ์„ ๊ถ๊ธˆํ•ดํ•˜๋Š” ์˜ํ™”์ด ๋“ค์–ด์˜ฌ ์ž…๋ ฅ์ฐฝ๊ณผ ๋ฒ„ํŠผ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๋Š” ์—”ํ„ฐํ‚ค๋ฅผ ๋ˆ„๋ฅด๊ฑฐ๋‚˜ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋นˆ ์ž…๋ ฅ์ฐฝ์—์„œ ์š”์ฒญ์„ ๋ฐœ์ƒ์‹œํ‚ค๋ ค๊ณ  ํ•˜๋ฉด alert() ๋ฉ”์†Œ๋“œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  ์š”์ฒญ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์š”์ฒญ์ด ๋ฐœ์ƒํ•  ๋•Œ ์ž…๋ ฅ์ฐฝ์€ ๋น„์›Œ์ง‘๋‹ˆ๋‹ค.
v-model ์‚ฌ์šฉ
  • v-model๋กœ input๊ณผ ๋ฐ”์ธ๋”ฉํ•ด์„œ ๊ด€๋ฆฌ๋˜๋Š” ๊ฐ’์ด๋‹ค. youtube API์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋งŒ ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ๋Š” ๋’ค์— 'trailer'๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ๋ณด๋ƒ…๋‹ˆ๋‹ค.

VideoItem.vue

์ปดํฌ๋„ŒํŠธ ์„ค๋ช…
  • ์˜ˆ๊ณ ํŽธ ์˜์ƒ๊ณผ ์ •๋ณด๋“ค์ด ๋“ค์–ด์˜ฌ ์˜์—ญ์ž…๋‹ˆ๋‹ค. VideoView์—์„œ videos๋ฅผ ์ „๋‹ฌ ๋ฐ›์•„ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์ธ VideoItemDetail์—๊ฒŒ ์˜์ƒ์„ ํ•˜๋‚˜์”ฉ ์ชผ๊ฐœ์„œ ์ „๋‹ฌํ•ด ์ค๋‹ˆ๋‹ค.
props
  • API ์š”์ฒญ ๊ฒฐ๊ณผ ๋ฐ›์•„์˜จ videos๋ฐฐ์—ด์ด ์ €์žฅ๋˜์–ด ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ ์ „๋‹ฌ ๋ฐ›์€ ๋ฐ์ดํ„ฐ์ž…๋‹ˆ๋‹ค.

VideoItemDetail.vue

props
  • ๋ถ€๋ชจ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ ์ „๋‹ฌ๋ฐ›์€ video ๊ฐ์ฒด์—์„œ ์˜์ƒ์„ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•œ videoId์™€ title์„ ์ด์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
computed
  • ์˜์ƒ์˜ URL source๋ฅผ ์ €์žฅํ•  ๋•Œ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

    <scrript>
    computed: {
        videoUrl() {
          return `https://www.youtube.com/embed/${this.video.id.videoId}`;
        }}
    </script>

Key ๊ด€๋ฆฌ

  • ๋กœ์ปฌ์—์„œ ์‹คํ–‰ํ•  ๋•Œ๋Š” .env.local ํŒŒ์ผ์— VUE_APP_YOUTUBE_API_KEY๋ผ๋Š” ๋ณ€์ˆ˜๋ช…์— ์ €์žฅํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ๋ถˆ๋Ÿฌ์˜ฌ ๋•Œ๋Š” process.env.๋ณ€์ˆ˜๋ช…์œผ๋กœ ๋ถˆ๋Ÿฌ์™€์„œ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

Netlify ๋ฐฐํฌ

โ— ์–ด๋ ค์› ๋˜ ์ 

image-20200603181411114

  • mixed content ์˜ค๋ฅ˜๊ฐ€ ๋– ์„œ ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ์ง€ ๊ณ ๋ฏผํ–ˆ์Šต๋‹ˆ๋‹ค.

โญ ํ•ด๊ฒฐ

// src/views/MovieView.vue

axios.get('https://www.json-generator.com/api/json/get/ceNyuXZmwi?indent=2')
  • ์ด ๋ถ€๋ถ„์„ http โ†’ https๋กœ ์ˆ˜์ •ํ•˜์—ฌ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ตฌํ˜„ ํ™”๋ฉด

๋ฉ”์ธ ํ™”๋ฉด

capture-1176931


์˜ํ™” ๊ฐ€์ ธ์˜จ ํ›„ ํ™”๋ฉด

capture-1176952


์˜ํ™” ์ •๋ณด ์ƒ์„ธ๋ณด๊ธฐ ๋ชจ๋‹ฌ ํ™”๋ฉด

capture-1176976


์˜ํ™” ์˜ˆ๊ณ ํŽธ ๊ฒ€์ƒ‰ ๋ฉ”์ธ ํ™”๋ฉด

capture-1177016


์˜ํ™” ์˜ˆ๊ณ ํŽธ ๊ฒ€์ƒ‰ ํ™”๋ฉด

capture-1177042


๋Š๋‚€์ 

์ฑ„๋ฆฐ

  • Vue.js๋ฅผ ๋ฐฐ์šฐ๊ธฐ๋งŒ ํ–ˆ์—ˆ๋Š”๋ฐ, ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ๋ฅผ ํ†ตํ•ด์„œ ์ง์ ‘ ์ฝ”๋“œ๋ฅผ ์งœ๋ณด๋ฉด์„œ props, ๋ถ€๋ชจ-์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ ๊ด€๊ณ„๋ฅผ ์ˆ™์ง€ํ•˜๊ณ , ์ดํ•ด๋„๋„ ๋†’์•„์กŒ์Šต๋‹ˆ๋‹ค.
  • ์ค‘๊ฐ„์ค‘๊ฐ„ ๋ง‰ํ˜”๋˜ ๋ถ€๋ถ„์„ ํ•ด๊ฒฐํ•˜๋ฉฐ img-fluid, v-bind concatenation๋“ฑ ์ƒˆ๋กœ์šด ๊ฐœ๋…์„ ๋ฐฐ์šธ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์ˆ˜๋ฏผ

  • vue์˜ ์ „์ฒด์ ์ธ ์ฒด๊ณ„๋ฅผ ์ง์ ‘ ๋งŒ๋“ค์–ด๋ณด๋ฉฐ ์ต์ˆ™ํ•ด์งˆ ์ˆ˜ ์žˆ์–ด ์ข‹์•˜์Šต๋‹ˆ๋‹ค.
  • vue์˜ ๋น„๋™๊ธฐ์ ์ธ ์„ฑํ–ฅ์„ ์ดํ•ดํ•˜๋ฉฐ ์ œ์ž‘ํ•  ์ˆ˜ ์žˆ์–ด ์ข‹์•˜์Šต๋‹ˆ๋‹ค.

์˜์ฐฌ

  • Vue๋ฅผ ์ด์šฉํ•œ ํ”„๋กœ์ ํŠธ๋ฅผ ์ฒ˜์Œ ์ง„ํ–‰ํ•ด๋ณด๋ฉด์„œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋ฐฐ์šฐ๋ฉด์„œ ๋ฐฐ์› ๋˜ ์ง€์‹๋“ค๊ณผ ๋น„๊ตํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.
  • axiosโ€ฉ๋ฅผ ์ด์šฉํ•œ ๋น„๋™๊ธฐ ํ†ต์‹ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์ด ์œ ์‚ฌํ•œ ๊ฒƒ์„ ํ™•์ธํ–ˆ๊ณ  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด๋ฅผ ๋‹ค์–‘ํ•˜๊ฒŒ ์ด์šฉํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.