Skip to content
Search

Vue Router

lastmod 2022-08-10created 2020-06-1531 edits

Vue Router is the official router for Vue.js. It is deeply integrated with the Vue.js core to make building single-page apps with Vue.js easy.

Features

It includes the following features.

  • Nested route/view mapping
  • Modular, component-based router configuration
  • Route params, query, wildcards
  • Transition effects using Vue.js' transition system
  • Fine-grained navigation control
  • Links that automatically add active CSS classes
  • HTML5 history mode or hash mode (automatic fallback in IE9)
  • Customizable scroll behavior

Getting started

Creating a single-page app with Vue and Vue Router is very easy. If you use Vue.js, you are already composing your app with components. When adding Vue Router to the mix, all you need to do is map your components to routes and tell it at which address to render them.

HTML

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

<div id="app">
  <h1>Hello App!</h1>
  <p>
    <!-- 네비게이션을 위해 router-link 컴포넌트를 사용합니다. -->
    <!-- 구체적인 속성은 `to` prop을 이용합니다. -->
    <!-- 기본적으로 `<router-link>`는 `<a>` 태그로 렌더링됩니다.-->
    <router-link to="/foo">Go to Foo</router-link>
    <router-link to="/bar">Go to Bar</router-link>
  </p>
  <!-- 라우트 아울렛 -->
  <!-- 현재 라우트에 맞는 컴포넌트가 렌더링됩니다. -->
  <router-view></router-view>
</div>

JavaScript

// 0. 모듈 시스템 (예: vue-cli)을 이용하고 있다면, Vue와 Vue 라우터를 import 하세요
// 그리고 `Vue.use(VueRouter)`를 호출하세요


// 1. 라우트 컴포넌트를 정의하세요.
// 아래 내용들은 다른 파일로부터 가져올 수 있습니다.
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }

// 2. 라우트를 정의하세요.
// Each route should map to a component. The "component" can
// 각 라우트는 반드시 컴포넌트와 매핑되어야 합니다.
// "component"는 `Vue.extend()`를 통해 만들어진
// 실제 컴포넌트 생성자이거나 컴포넌트 옵션 객체입니다.
const routes = [
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
]

// 3. `routes` 옵션과 함께 router 인스턴스를 만드세요.
// 추가 옵션을 여기서 전달해야합니다.
// 지금은 간단하게 유지하겠습니다.
const router = new VueRouter({
  routes // `routes: routes`의 줄임
})

// 4. 루트 인스턴스를 만들고 mount 하세요.
// router와 router 옵션을 전체 앱에 주입합니다.
const app = new Vue({
  router
}).$mount('#app')

// 이제 앱이 시작됩니다!

By injecting the router, you can access it as this.$router and the current route as this.$route.

// Home.vue
export default {
  computed: {
    username () {
      // 곧 `params` 확인할 수 있습니다.
      return this.$route.params.username
    }
  },
  methods: {
    goBack () {
      window.history.length > 1
        ? this.$router.go(-1)
        : this.$router.push('/')
    }
  }
}

Throughout the documentation, router is used often. this.$router is exactly the same as router. The reason to use this.$router is that you don't need to import the route object in every component that has to manipulate the router.

You can check it out right away in this example.

<router-link> automatically gets the .router-link-active class when it matches the current route. See the API reference.

<router-link> is the component for enabling user navigation in a router-enabled app. The target location is specified with the to prop. By default it renders as an <a> tag with the correct href, but this can be configured with the tag prop. In addition, the link automatically gets an active CSS class when the target route is active.

<router-link> is preferred over a hard-coded <a href="..."> for the following reasons.

  • It works the same way in both HTML5 history mode and hash mode, so if you decide to switch modes or the router falls back to hash mode in IE9, nothing needs to change.
  • In HTML5 history mode, router-link intercepts the click event so that the browser doesn't reload the page.
  • When using the base option in HTML5 history mode, you don't need to include it in the URL of the to prop.

Dynamic route matching

Nested routes

Programmatic navigation

Named routes

Named views

Redirect and alias

Passing props to route components

There are two ways to pass data with vue router: query and params.

Query

{name: 'Query', query: {name: 'cat', age: 3}}

Receiving:

<template>
  <div>
    <h1>Query</h1>

    <h2>name: {{ $route.query.name }}</h2>
    <h2>age: {{ $route.query.age }}</h2>
  </div>
</template>

<script>
    export default {
        name: 'Query',
    }
</script>

Params

{name: 'Params', params: {name: 'dog', age:4}}

Receiving:

<template>
  <div>
    <h1>Params</h1>

    <h2>params로 받은 데이터</h2>
    <h2>name: {{ $route.params.name }}</h2>
    <h2>age: {{ $route.params.age }}</h2>

    <h2>props로 받은 데이터</h2>
    <h2>name: {{ name }}</h2>
    <h2>age: {{ age }}</h2>
  </div>
</template>

<script>
    export default {
        name: 'Params',
        props: {
            name: {
                type: String,
                default : ''
            },
            age: {
                type: Number,
                default: 0
            }
        }
    }
</script>

WARNING

When using the Params approach, note that it only works correctly if you use named paths. 1

Example

<template>
  <div>
    main

    <ul>
      <li @click="clickList">
        Query 프로그래밍 방식
      </li>
      <router-link :to="{name: 'Query', query: {name: 'cat', age: 3}}">
        Query 선언적 방식
      </router-link>
      <li @click="clickParams">
        params
      </li>
      <router-link :to="{name: 'Params', params: {name: 'dog', age:4}}">
        params 선언적 방식
      </router-link>
    </ul>
  </div>
</template>

<script>
    export default {
        name: 'Main',
        methods: {
            clickList () {
                this.$router.push({name: 'Query', query: {name: 'cat', age: 3}})
            },
            clickParams () {
                this.$router.push({name: 'Params', params: {name: 'dog', age:4}})
            }
        }
    }
</script>

HTML5 history mode

const router = new VueRouter({
  mode: 'history',
  routes: [...]
})

This makes the hashbang (#) disappear.

Caveats when deploying in history mode

If you deploy to $URL/app/, all absolute-path routes must also be changed to that path. You can refer to the publicPath variable in the vue.config.js file. For example, you can do it as follows.

export const PUBLIC_PATH = require('@/../vue.config').publicPath;
export const rootChildren = [
    {
        path: PUBLIC_PATH + 'init',
        component: Init,
        name: rootNames.init,
    },
    // ...
];

As you will see in HTML5 history mode # Example server configurations, all routing paths must be forwarded to the index.html file.

Apache

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.html [L]
</IfModule>

nginx

location / {
  try_files $uri $uri/ /index.html;
}

Native Node.js

const http = require('http')
const fs = require('fs')
const httpPort = 80

http
  .createServer((req, res) => {
    fs.readFile('index.html', 'utf-8', (err, content) => {
      if (err) {
        console.log('We cannot open "index.html" file.')
      }

      res.writeHead(200, {
        'Content-Type': 'text/html; charset=utf-8'
      })

      res.end(content)
    })
  })
  .listen(httpPort, () => {
    console.log('Server listening on: http://localhost:%s', httpPort)
  })

aiohttp

With aiohttp, you can use the aiohttp.web.static function as follows, but...

from aiohttp import web

# ...
app = web.Application()
app.router.add_routes([
    web.static('/www/deploy/path')
])

Since routing happens as $URL/$routingPaths rather than $URL/index.html, the approach above cannot be used. Above all, the aiohttp.web.static function turns into a directory listing when routing to the $URL/ path, so it must not be used. (Because vue-router can route to /.)

For reference, as in the following example...

from aiohttp import web

# ...
app = web.Application()
app.router.add_routes([
    web.get('/{tail:.*}', self.on_default_route),
    web.static('/', '/www/deploy/path'),
])

...the approach using a regex like '/{tail:.*}' also ended up causing problems...

devServer

This is webpack-dev-server. For reference, the development server of vue-cli uses it.

Capturing route-view events

Restricting access by permission

replace

this.$router.replace({
   name: "error",
   params: { 0: `/${this.$route.path}` },
   replace: true,
});

Troubleshooting

Not found

The routing options were set as follows.

export const routes = [
    {
        path: 'init',
        component: Init,
        name: 'init',
    },
    {
        path: 'signin',
        component: Signin,
        name: 'signin',
    },
    {
        path: '*',
        component: Error,
    }
];

With Signin configured to move to Init when not yet initialized, accessing http://localhost:8080/signin kept redirecting to the Error page.

In this case, setting the path attribute to '/init' instead of 'init' makes it work correctly.

Avoided redundant navigation to current location

The following error may occur when routing.

vue-router.esm.js?8c4f:2065 Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location: "/main/projects".

This error occurs when the path is the same. Check whether the path is the same first, then route.

if (this.$router.currentRoute.path !== '/main/projects') {
  this.$router.push('/main/projects');
}

Setting the default page of

A component page with children paths contains a , and navigating directly to that page displays an empty page.

    <router-view>
    </router-view>

In this case, you can add an entry whose path is an empty string, with redirect pointing to one of the children, as follows.

        children: [
          {
            path: '',
            redirect: 'overview',
          },
          {
            path: 'overview',
            component: OverviewPage,
          },
import Vue from 'vue';
import VueRouter from 'vue-router';
import { UserService } from './../service/user.service';
import store from './../store';

Vue.use(VueRouter);

...(생략)

const originalPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location) {
    return originalPush.call(this, location).catch(err => {
        if (err.name !== 'NavigationDuplicated') throw err;
    });
};

export default router;

Alternatively, check the current path (this.$router.currentRoute.path) before navigating.

    moveTo(location: RawLocation) {
        if (this.$router.currentRoute.path === location.toString()) {
            return;
        }

        this.$router.push(location).catch((reason: any) => {
            if (reason.name !== 'NavigationDuplicated') {
                throw reason;
            }
        })
    }

Named Route 'Main' has a default child route.

vue-router.esm.js?8c4f:16 [vue-router] Named Route 'Main' has a default child route. When navigating to this named route (:to="{name: 'Main'"), the default child route will not be rendered. Remove the name from this route and use the name of the default child route for named links instead.

If an error like the above occurs, check where the routes are configured.

export const Routes = [
    {
        path: '/main',
        component: Main,
        name: 'Main',
        meta: {requiresAuth: true},
        children: [
            {
                path: '',
                redirect: 'dashboard',
            },
            {
                path: 'dashboard',
                component: MainDashboard,
                name: Names.mainDashboard,
            },
        ],
    },
    ...
];

For a route with a children property as above, remove the name property and add the name property to the default routing path (the children route with path: '').

The correct result is as follows.

export const Routes = [
    {
        path: '/main',
        component: Main,
        meta: {requiresAuth: true},
        children: [
            {
                path: '',
                name: 'Main',
                redirect: 'dashboard',
            },
            {
                path: 'dashboard',
                component: MainDashboard,
                name: 'MainDashboard',
            },
        ],
    },
    ...
];

How to remove hashbang (#)

Use history mode.

const router = new VueRouter({
  mode: 'history',
  routes: [...]
})

See also

Favorite site

References

author Zer0 sitemap