DEV Community

Cover image for Navigation between views in Vue with Vue Router
Johnny Simpson
Johnny Simpson

Posted on • Originally published at fjolt.com

Navigation between views in Vue with Vue Router

After creating an application in Vue, you'll often want it to consist of multiple views or pages. To do this, we need to use an additional package known as vue-router. Creating a simple Vue application is easy, so in this guide we'll be looking at how you can add vue-router to your new application. To create your app in the first place, you only have to run the following commands:

npm i -g @vue/cli 
vue create my-app
Enter fullscreen mode Exit fullscreen mode

Then, adding a router to your application so you can navigate between pages, is also equally easy. Simply run the following command as well:

vue add router
Enter fullscreen mode Exit fullscreen mode

You may be asked if you want to use history mode. You can type Y to this, if you have no preference. After that, you'll get a few more folders and files in your project. Your overall structure should look a little like this:

- public
--- favicon.ico
--- index.html
- src
--- assets
--- components
--- router
------ index.js
--- views
------ About.vue
------ Home.vue
--- App.vue
--- main.js
- package.json
- package-lock.json
Enter fullscreen mode Exit fullscreen mode

As you can see, you now have a number of new files for the router - and a few changes to your existing files. For example, in main.js, your application will be using the router folder that has now been created. The index.js file will be imported as shown below:

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

createApp(App).use(router).mount('#app')
Enter fullscreen mode Exit fullscreen mode

Modifying your Vue Router

In your /router/index.js file, you'll find the configuration for your router! It's here where you can set up pages. By default, you'll find your router looking a little like this:

import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router
Enter fullscreen mode Exit fullscreen mode

So there are two ways to add routes, as shown above. You can import using the import() function, or import using the typical Javascript import statement. Each route has 3 different parts:

  • the path, which is the URL the user will be able to navigate to.
  • the name of the page, which is the identifier for the page.
  • the component for the page. This is the component which will appear when the user navigates to the path.
{
    path: '/',
    name: 'Home',
    component: Home
}
Enter fullscreen mode Exit fullscreen mode

To add more, you just need to add more to the object - so below I've added in a new page called /contact-us, using a component found in '../views/ContactUs.vue':


import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/contact-us',
    name: 'ContactUs',
    component: () => import('../views/ContactUs.vue')
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router
Enter fullscreen mode Exit fullscreen mode

Dynamic Routing with Vue Router

So, that's all good, but what if your URL endpoint isn't static? For example, /user/:id, where :id could be anything at all. Fortunately, that is also possible, simply by writing the URL in that format - you just have to write /user/:id in the path property:

{
    path: '/user/:name',
    name: 'User',
    component: () => import('../views/User.vue')
}
Enter fullscreen mode Exit fullscreen mode

The matching format for vue-router is familiar, if you've used express - and in fact any route matching you can do in express, you can do in vue-router.

Redirection with Vue Router

Finally, we can also set a route to redirect to another one. You can do this using the redirect property. For example, the below will redirect /home to /homepage:

{
    path: '/home',
    name: 'home',
    redirect: '/homepage'
}
Enter fullscreen mode Exit fullscreen mode

This can also be defined as a named route. Below, we will redirect /home to whichever route has the name about:

{
    path: '/home',
    name: 'home',
    redirect: { name: 'about' }
}
Enter fullscreen mode Exit fullscreen mode

And finally, you can also define this as a function.. meaning you can create some more complex logic to handle the redirection:

{
    path: '/user/:id',
    name: 'home',
    redirect: (to) => {
        // to will contain information about the route
        // to.params.id will be whichever `id` is in the URL in /user/:id
    }
}
Enter fullscreen mode Exit fullscreen mode

Navigating Between Pages with Vue Router

Now that we have defined our router, we'll want to use it in our application. You may notice that your App.vue file has changed slightly, and contains something like this:

<template>
    <div id="nav">
        <router-link to="/">Home</router-link> |
        <router-link to="/about">About</router-link>
    </div>
    <router-view/>
</template>
Enter fullscreen mode Exit fullscreen mode

The <router-link> tag can be used to easily navigate between routes defined in your router index.js file. The <router-view> tag will ultimately contain your routes, once they are clicked on. Each route will also contain their own <router-view>, though, which means you can have nested routes. These can all be defined in /routes/index.js. For example, here is a nested route where it contains two potential children, dashboard, and posts:

const routes = [
    {
        path: '/user/:name',
        name: 'User',
        component: import('../views/User.vue'),
        children: [{
            path: 'dashboard',
            component: import('../views/Dashboard.vue'),
        },
        {
            path: 'posts',
            component: import('../views/Posts.vue'),
        }]
    }
]
Enter fullscreen mode Exit fullscreen mode

Now, since we have defined child components, we can still use the /user/:name path, but now have two additional components which will be rendered within User.vue, accessible via /user/:name/dashboard and /user/:name/posts respectively. So while User is rendered within the App.vue <router-view>, dashboard and posts will be rendered within the User.vue version of <router-view>. It looks a bit like this:

┌ - - - - - - - - - - - - - - - - - - ┐
| App.vue                             |
| ┌ - - - - - - - - - - - - - - - - ┐ |
| | User.vue                        | | 
| | ┌ - - - - - - - ┐ ┌ - - - - - ┐ | |
| | | Dashboard.vue | | Posts.vue | | |
| | └ - - - - - - - ┘ └ - - - - - ┘ | |
| └ - - - - - - - - - - - - - - - - ┘ |
└ - - - - - - - - - - - - - - - - - - ┘
Enter fullscreen mode Exit fullscreen mode

That ultimately means the User.vue component will always be visible when you navigate to /user/:name, but the Dashboard.vue and Posts.vue component will only become visible if you navigate to those routes!

Programatic Routing with Vue Router

Just like how we used <router-link>, we can also programmatically navigate to a route using router.push. <router-link to="/about"> can similarly be written like this in Javascript:

router.push('/about')
Enter fullscreen mode Exit fullscreen mode

If we want to be a little more advanced, we can pass in an object. For example, the below will navigate programmatically to the route with a name defined as About, and add a query string of ?id=15 to the end. If the About route has a path of /about, then the URL this will redirect to would be /about/?id=15:

router.push({ name: 'About', query: { id : 15 }})
Enter fullscreen mode Exit fullscreen mode

Similarly, the same Javascript could be represented in HTML as so:

<router-link to="{ name: 'About', query: { id : 15 }}">About</router-link>
Enter fullscreen mode Exit fullscreen mode

Preventing the back button with Vue Router

While this will add a new history entry for the user navigating, we can also replace the current page for the user - which means that no history or back button to the previous page will be available. This is generally not advisable, but will have some limited use in some situations. To do that programmatically, we can use router.replace:

router.replace({ name: 'About', query: { id : 15 }})
Enter fullscreen mode Exit fullscreen mode

Or in HTML, append the replace attribute:

<router-link to="{ name: 'About', query: { id : 15 }}" replace>About</router-link>
Enter fullscreen mode Exit fullscreen mode

Conclusion

I hope you've enjoyed this guide to getting started with the vue router. Routers in Vue are an invaluable part of setting up a new application, and give us so much flexibility to define and build pages within Vue. To learn more about Vue, check out my other guides.

Top comments (0)