# ๋ทฐ ๋ผ์šฐํ„ฐ

๋ทฐ ๋ผ์šฐํ„ฐ๋Š” ๋ทฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•˜์—ฌ ์‹ฑ๊ธ€ ํŽ˜์ด์ง€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌํ˜„ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.

# ๋ทฐ ๋ผ์šฐํ„ฐ ์„ค์น˜

ํ”„๋กœ์ ํŠธ์— ๋ทฐ ๋ผ์šฐํ„ฐ๋ฅผ ์„ค์น˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ CDN ๋ฐฉ์‹๊ณผ NPM ๋ฐฉ์‹ 2๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

# CDN ๋ฐฉ์‹

<script src="https://unpkg.com/vue-router/dist/vue-router.js">

# NPM ๋ฐฉ์‹

npm install vue-router

# ๋ทฐ ๋ผ์šฐํ„ฐ ๋“ฑ๋ก

๋ทฐ ๋ผ์šฐํ„ฐ๋ฅผ ์„ค์น˜ํ•˜๊ณ  ๋‚˜๋ฉด ์•„๋ž˜ ์ฝ”๋“œ์™€ ๊ฐ™์ด ๋ผ์šฐํ„ฐ ์ธ์Šคํ„ด์Šค๋ฅผ ํ•˜๋‚˜ ์ƒ์„ฑํ•˜๊ณ  ๋ทฐ ์ธ์Šคํ„ด์Šค์— ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.

// ๋ผ์šฐํ„ฐ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
var router = new VueRouter({
  // ๋ผ์šฐํ„ฐ ์˜ต์…˜
})

// ์ธ์Šคํ„ด์Šค์— ๋ผ์šฐํ„ฐ ์ธ์Šคํ„ด์Šค๋ฅผ ๋“ฑ๋ก
new Vue({
  router: router
})

# ๋ทฐ ๋ผ์šฐํ„ฐ ์˜ต์…˜

์œ„์™€ ๊ฐ™์ด ๋ผ์šฐํ„ฐ๋ฅผ ๋“ฑ๋กํ•˜๊ณ  ๋‚˜๋ฉด ๊ทธ ๋‹ค์Œ์— ํ•  ์ผ์€ ๋ผ์šฐํ„ฐ์— ์˜ต์…˜์„ ์ •์˜ํ•˜๋Š” ์ผ์ž…๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ SPA ์•ฑ์—์„œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด 2๊ฐœ ์˜ต์…˜์„ ํ•„์ˆ˜๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

  • routes : ๋ผ์šฐํŒ… ํ•  URL๊ณผ ์ปดํฌ๋„ŒํŠธ ๊ฐ’ ์ง€์ •
  • mode : URL์˜ ํ•ด์‰ฌ ๊ฐ’ ์ œ๊ฑฐ ์†์„ฑ

๊ทธ๋Ÿผ ์œ„ ์˜ต์…˜์œผ๋กœ ๋ผ์šฐํ„ฐ๋ฅผ ์ •์˜ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

new VueRouter({
  mode: 'history',
  routes: [
    { path: '/login', component: LoginComponent },
    { path: '/home', component: HomeComponent }
  ]
})

์œ„ ์ฝ”๋“œ๋Š” ๋ผ์šฐํŒ…์„ ํ•  ๋•Œ URL์— # ๊ฐ’์„ ์ œ๊ฑฐํ•˜๊ณ , URL ๊ฐ’์ด /login๊ณผ /home์ผ ๋•Œ ๊ฐ๊ฐ ๋กœ๊ทธ์ธ ์ปดํฌ๋„ŒํŠธ์™€ ํ™ˆ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฟŒ๋ ค์ค๋‹ˆ๋‹ค.

# router-view

๋ธŒ๋ผ์šฐ์ €์˜ ์ฃผ์†Œ ์ฐฝ์—์„œ URL์ด ๋ณ€๊ฒฝ๋˜๋ฉด, ์•ž์—์„œ ์ •์˜ํ•œ routes ์†์„ฑ์— ๋”ฐ๋ผ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ™”๋ฉด์— ๋ฟŒ๋ ค์ง‘๋‹ˆ๋‹ค. ์ด ๋•Œ ๋ฟŒ๋ ค์ง€๋Š” ์ง€์ ์ด ํ…œํ”Œ๋ฆฟ์˜ <router-view>์ž…๋‹ˆ๋‹ค.

<div id="app">
  <router-view></router-view> <!-- LoginComponent ๋˜๋Š” HomeComponent -->
</div>

์•ž์—์„œ ์ •์˜ํ•œ ๋ผ์šฐํŒ… ์˜ต์…˜ ๊ธฐ์ค€์œผ๋กœ /login์€ ๋กœ๊ทธ์ธ ์ปดํฌ๋„ŒํŠธ๋ฅผ /home์€ ํ™ˆ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ™”๋ฉด์— ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ ์›น ํŽ˜์ด์ง€์—์„œ ํŽ˜์ด์ง€ ์ด๋™์„ ํ•  ๋•Œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ url์„ ๋‹ค ์ณ์„œ ์ด๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ๋•Œ ํ™”๋ฉด์—์„œ ํŠน์ • ๋งํฌ๋ฅผ ํด๋ฆญํ•ด์„œ ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜์•ผ ํ•˜๋Š”๋ฐ ๊ทธ๊ฒŒ ๋ฐ”๋กœ <router-link> ์ž…๋‹ˆ๋‹ค.

<router-link to="์ด๋™ํ•  URL"></router-link>

์‹ค์ œ ์ฝ”๋“œ ์˜ˆ์‹œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

<div>
  <router-link to="/login"></router-link>
</div>

์œ„ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ํ™”๋ฉด์—์„œ๋Š” <a> ํƒœ๊ทธ๋กœ ๋ณ€ํ˜•๋˜์„œ ๋‚˜์˜ต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ <a> ํƒœ๊ทธ๋ฅผ ํด๋ฆญํ•˜๋ฉด /login URL๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

# ๊ธฐํƒ€ ๋ผ์šฐํ„ฐ ์˜ต์…˜๊ณผ ๊ธฐ๋ฒ•

์œ„์˜ ๋‚ด์šฉ์œผ๋กœ๋„ ๊ฐ„๋‹จํ•œ ๋ผ์šฐํŒ…์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ๋‹จ๋ฝ์—์„œ๋Š” ๊ธฐํƒ€ ๋ผ์šฐํ„ฐ API์™€ ์‹ค๋ฌด์—์„œ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ๋ผ์šฐํ„ฐ ์˜ต์…˜๋“ค์„ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

# ๋™์  ๋ผ์šฐํŠธ ๋งค์นญ

๋™์  ๋ผ์šฐํŠธ ๋งค์นญ(Dynamic Route Matching)์€ ํŠน์ • ํŒจํ„ด์„ ๊ฐ€์ง„ ๊ฒฝ๋กœ๋“ค์„ ๋™์ผํ•œ ์ปดํฌ๋„ŒํŠธ์— ๋งคํ•‘ํ•ด์•ผ ํ•  ๊ฒฝ์šฐ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋ฒ•์ž…๋‹ˆ๋‹ค.
๋™์  ๋ผ์šฐํŠธ ๋งค์นญ์˜ ์˜ˆ์‹œ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ผ์šฐํ„ฐ๊ฐ€ ์ •์˜๋˜์—ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

new VueRouter({
  routes: [
    { path: '/resume/:year', component: ResumeComponent }
  ]
})

์œ„ ์ฝ”๋“œ์™€ ๊ฐ™์ด ๋ผ์šฐํ„ฐ๋ฅผ ์ •์˜ํ•˜๋ฉด path์—์„œ ์ฝœ๋ก (:)์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ถ€๋ถ„(๋™์  ์„ธ๊ทธ๋จผํŠธ)์ด ๋‹ค๋ฅด๋”๋ผ๋„ ๊ฐ™์€ ๊ฒฝ๋กœ์— ๋งคํ•‘๋ฉ๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ /resume/2020๊ณผ /resume/2021 ๊ฐ™์€ URL์ด ๋ชจ๋‘ ResumeComponent ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณด์—ฌ์ฃผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
๋˜ํ•œ :year ์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ’์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์—์„œ this.$route.params ๋ฅผ ํ†ตํ•ด ๊ฐ€์ ธ์™€์„œ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<!-- ResumeComponent.vue -->
<template>
  <h1>{{ $route.params.year }}</h1>
</template>

# ์ปดํฌ๋„ŒํŠธ์— props ์ „๋‹ฌํ•˜๊ธฐ

์•ž์„œ ๋™์  ๋ผ์šฐํŠธ ๋งค์นญ์—์„œ ์‚ดํŽด๋ณธ ๊ฒƒ์ฒ˜๋Ÿผ ์ปดํฌ๋„ŒํŠธ์—์„œ $route๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ผ์šฐํ„ฐ ์†์„ฑ์— ์˜์กดํ•˜๊ฒŒ ๋˜์–ด ํŠน์ • URL์—์„œ๋งŒ ์‚ฌ์šฉ๋œ๋‹ค๋Š” ๋ฌธ์ œ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
์ด ์˜์กด์„ฑ ํ•ด์ œ๋ฅผ ์œ„ํ•ด ์ปดํฌ๋„ŒํŠธ์™€ ๋ผ์šฐํ„ฐ ์†์„ฑ์„ ๋ถ„๋ฆฌํ•˜๋ ค๋ฉด ์†์„ฑ props์— true๋ฅผ ์ „๋‹ฌํ•ด์ค๋‹ˆ๋‹ค.

new VueRouter({
  routes: [
    { path: '/resume/:year', component: ResumeComponent, props: true }
  ]
})

์œ„ ์ฝ”๋“œ์™€ ๊ฐ™์ด props๊ฐ€ true๋กœ ์ ์šฉ๋˜๋ฉด :year์— ํ•ด๋‹นํ•˜๋Š” ๋ถ€๋ถ„์ด year๋ผ๋Š” props๋กœ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.
์ด๋ฅผ ํ†ตํ•ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ผ์šฐํ„ฐ ์†์„ฑ์— ์˜์กดํ•˜์ง€ ์•Š๊ณ  ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.



ย 




ย 



<!-- ResumeComponent.vue -->
<template>
  <h1>{{ year }}</h1>
</template>

<script>
export default {
  props: ['year']
}
</script>

# ๋ผ์šฐํ„ฐ ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฉ”์„œ๋“œ

๋ผ์šฐํ„ฐ API์—๋Š” <router-link>๋กœ ์›น ํŽ˜์ด์ง€ ์ด๋™์„ ์œ„ํ•œ <a> ํƒœ๊ทธ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ• ์™ธ์—๋„ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ ์œผ๋กœ ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
Vue ์ธ์Šคํ„ด์Šค ๋‚ด๋ถ€์—์„œ ๋ผ์šฐํ„ฐ ์ธ์Šคํ„ด์Šค์— ์ ‘๊ทผํ•˜๋ ค๋ฉด $router๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

# router.push()

router.push(location, onComplete?, onAbort?)

<router-link>์˜ to ์†์„ฑ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ํžˆ์Šคํ† ๋ฆฌ์— ํ˜„์žฌ ํŽ˜์ด์ง€๋ฅผ ์ €์žฅํ•œ ๋’ค ์ธ์ž๋กœ ์ „๋‹ฌ๋ฐ›์€ URL(location)๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

// string ์ „๋‹ฌ
this.$router.push('home'); 

// object ์ „๋‹ฌ  
this.$router.push({ path: 'home' }); 

const postId = "1";
this.$router.push({ path: `/posts/${postId}` }); // โ†’ /posts/1

// query์™€ ํ•จ๊ป˜ ์ „๋‹ฌ 
this.$router.push({ path: 'user', query: { id: 'captain' } }); // โ†’ /user?id=captain

onComplete์™€ onAbort๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋กœ, onComplete๋Š” ๋„ค๋น„๊ฒŒ์ด์…˜์ด ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋˜์—ˆ์„ ๊ฒฝ์šฐ ํ˜ธ์ถœ๋˜๊ณ , onAbort๋Š” ํ˜„์žฌ ๋„ค๋น„๊ฒŒ์ด์…˜์ด ์™„๋ฃŒ๋˜๊ธฐ ์ „ ๋™์ผํ•œ ๊ฒฝ๋กœ๋กœ ์ด๋™ํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ๊ฒฝ๋กœ๋กœ ์ด๋™๋  ๋•Œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

export default {
  methods: {
    click() {
      this.$router.push("/home", this.completeHandler, this.abortHandler);
    },
    completeHandler() {
      console.log("complete");
    },
    abortHandler() {
      console.log("abort");
    },
  },
};

# router.replace()

router.replace(location, onComplete?, onAbort?)

ํžˆ์Šคํ† ๋ฆฌ์— ํ˜„์žฌ ํŽ˜์ด์ง€๋ฅผ ์ €์žฅํ•˜์ง€ ์•Š๊ณ  ์ด๋™ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํžˆ์Šคํ† ๋ฆฌ์— ๊ฒฝ๋กœ๊ฐ€ ๋‚จ์ง€ ์•Š์œผ๋ฏ€๋กœ ๋ฐฑ์ŠคํŽ˜์ด์Šคํ‚ค๋ฅผ ๋ˆŒ๋ €์„ ๋•Œ ์›๋ž˜ ํŽ˜์ด์ง€๋กœ ๋Œ์•„์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋ฆ„์— ๋‚˜ํƒ€๋‚˜๋“ฏ์ด ํ˜„์žฌ ํŽ˜์ด์ง€๊ฐ€ ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋กœ ๋Œ€์ฒด๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์‚ฌ์šฉํ•˜๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” router.push ๋ฉ”์„œ๋“œ์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

this.$router.replace('home');

# router.go()

router.go(n)

ํžˆ์Šคํ† ๋ฆฌ ์Šคํƒ์—์„œ ์•ž ๋˜๋Š” ๋’ค๋กœ ์ „๋‹ฌ๋œ ์ธ์ž(์ •์ˆ˜)๋งŒํผ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

this.$router.go(-1); // ์ด์ „ ํŽ˜์ด์ง€๋กœ ์ด๋™

this.$router.go(1);  // ๋‹ค์Œ ํŽ˜์ด์ง€๋กœ ์ด๋™ 

# ๋ผ์šฐํ„ฐ ๋ฉ”ํƒ€ ํ•„๋“œ

๋ผ์šฐํ„ฐ๋ฅผ ์ •์˜ํ•  ๋•Œ meta ํ•„๋“œ๋ฅผ ํ†ตํ•ด ์›ํ•˜๋Š” ๋ฉ”ํƒ€ ์ •๋ณด๋ฅผ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•œ ๋ผ์šฐํŒ…์ธ์ง€ ์•„๋‹Œ์ง€ ๊ตฌ๋ถ„ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์— ํ™œ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋กœ๊ทธ์ธ ํ•„์š” ์—ฌ๋ถ€ ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ๋Š” ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐ€๋“œ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

new VueRouter({
  routes: [
    // authRequired: true ๋ผ๋Š” ๋ฉ”ํƒ€ ํ•„๋“œ ์ž…๋ ฅ
    { path: '/orders', component: OrdersComponent, meta: { authRequired: true } }
  ]
})

# ์ฝ”๋“œ ๋ถ„ํ• 

Webpack๊ณผ ๊ฐ™์€ ๋ฒˆ๋“ค๋Ÿฌ๋ฅผ ์ด์šฉํ•ด ์•ฑ์„ ์ œ์ž‘ํ•˜๋ฉด ํŒŒ์ผ์ด ์ปค์ ธ ํŽ˜์ด์ง€ ๋กœ๋“œ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒ˜์Œ์— ๋ Œ๋”๋ง์— ํ•„์š”ํ•œ ๋ชจ๋“  ํŒŒ์ผ์„ ๋กœ๋“œํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๊ฒฝ๋กœ์— ๋งž์ถฐ ๋‹น์žฅ ๋ Œ๋”๋ง์ด ํ•„์š”ํ•œ ํŒŒ์ผ๋งŒ ๋กœ๋“œํ•˜๋Š” ๊ฒƒ์ด ํšจ์œจ์ ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋ฒ•์ด ์ฝ”๋“œ ๋ถ„ํ• ์ž…๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋ผ์šฐํ„ฐ์˜ ์ฝ”๋“œ ๋ถ„ํ•  ๋ฌธ๋ฒ•์„ ์ฐธ๊ณ ํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.