Skip to main content

Vue.js Router Introduction

What is Vue Router?​

Vue Router is the official routing library for Vue.js applications. It allows you to create Single-Page Applications (SPAs) by mapping components to different routes, enabling navigation between pages without reloading the entire application. This results in a smoother, faster user experience that feels more like a native application.

Why Do We Need a Router?​

Traditional websites load a new HTML page from the server whenever a user navigates to a new URL. In contrast, Single-Page Applications load a single HTML page and dynamically update the content as users navigate through the application.

A router helps manage this dynamic content swapping by:

  1. Matching URLs to components
  2. Handling navigation
  3. Managing application state during navigation
  4. Providing features like route parameters and nested routes

Setting up Vue Router​

Installation​

For a new Vue.js project using Vue CLI, you can select the router option during project creation. For an existing project, install Vue Router with npm or yarn:

bash
# Using npm
npm install vue-router

# Using yarn
yarn add vue-router

Basic Configuration​

To set up Vue Router in your Vue.js application, you need to:

  1. Create a router instance
  2. Define routes
  3. Link the router to your Vue application

Here's a basic example:

js
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import About from '../views/About.vue'

const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: About
}
]

const router = createRouter({
history: createWebHistory(),
routes
})

export default router

Then, in your main.js file:

js
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

const app = createApp(App)
app.use(router)
app.mount('#app')

Using Vue Router in Templates​

Once your router is set up, you can use the router-specific components in your templates.

The <router-view> Component​

The <router-view> component is a placeholder where the component matching the current route will be rendered:

html
<template>
<div id="app">
<header>
<!-- Navigation links -->
</header>

<!-- The component matching the current route will be rendered here -->
<router-view></router-view>

<footer>
<!-- Footer content -->
</footer>
</div>
</template>

The <router-link> component is used for navigation in your application. It renders as an <a> tag but prevents the browser from reloading the page:

html
<template>
<div id="app">
<nav>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</nav>
<router-view></router-view>
</div>
</template>

Understanding Route Objects​

Each route object in the routes array can have several properties:

js
{
path: '/user/:id', // URL pattern
name: 'User', // Named route for programmatic navigation
component: User, // Component to render
props: true, // Pass route params as props to the component
meta: { requiresAuth: true } // Custom metadata
}

Dynamic Routes​

You can create dynamic routes using path parameters:

js
const routes = [
{
path: '/user/:id',
name: 'User',
component: User,
props: true
}
]

In the User component, you can access the id parameter:

html
<template>
<div>
<h2>User Profile</h2>
<p>User ID: {{ id }}</p>
</div>
</template>

<script>
export default {
props: ['id'], // When props:true is used in the route, params become props

// Alternative approach using $route
computed: {
userId() {
return this.$route.params.id
}
}
}
</script>

Programmatic Navigation​

Besides using <router-link>, you can navigate programmatically using the router instance:

js
// Navigate to a specific path
this.$router.push('/about')

// Navigate using route name and params
this.$router.push({ name: 'User', params: { id: '123' } })

// Navigate with query parameters
this.$router.push({ path: '/search', query: { q: 'vue router' } })

// Go back in history
this.$router.back()

// Go forward in history
this.$router.forward()

Nested Routes​

Vue Router supports nested routes, which are especially useful for complex layouts:

js
const routes = [
{
path: '/user/:id',
name: 'User',
component: User,
children: [
{
path: 'profile',
name: 'UserProfile',
component: UserProfile
},
{
path: 'posts',
name: 'UserPosts',
component: UserPosts
}
]
}
]

In the User component, you need to include another <router-view> to render nested routes:

html
<template>
<div>
<h2>User {{ id }}</h2>
<nav>
<router-link :to="`/user/${id}/profile`">Profile</router-link> |
<router-link :to="`/user/${id}/posts`">Posts</router-link>
</nav>
<router-view></router-view>
</div>
</template>

Route Guards​

Vue Router provides navigation guards to control navigation. These guards can be global, per-route, or in-component:

Global Guards​

js
// Global before guard
router.beforeEach((to, from, next) => {
// Check if route requires authentication
if (to.meta.requiresAuth && !isAuthenticated) {
next('/login')
} else {
next() // Allow navigation
}
})

// Global after guard
router.afterEach((to, from) => {
document.title = to.meta.title || 'My Vue App'
})

Route-Specific Guards​

js
const routes = [
{
path: '/admin',
component: Admin,
beforeEnter: (to, from, next) => {
if (isAdmin) {
next()
} else {
next('/unauthorized')
}
}
}
]

In-Component Guards​

js
export default {
name: 'User',
beforeRouteEnter(to, from, next) {
// Called before the component is created
// "this" is not available here
fetchUser(to.params.id, (user) => {
next(vm => {
vm.userData = user
})
})
},
beforeRouteUpdate(to, from, next) {
// Called when route changes but component is reused
// "this" is available
this.userData = null
fetchUser(to.params.id, (user) => {
this.userData = user
next()
})
},
beforeRouteLeave(to, from, next) {
// Called when navigating away from this component
// "this" is available
if (this.hasUnsavedChanges) {
if (!confirm('You have unsaved changes. Are you sure you want to leave?')) {
return next(false)
}
}
next()
}
}

Real-World Example: Building a Blog​

Let's create a simple blog application with Vue Router:

js
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import BlogList from '../views/BlogList.vue'
import BlogPost from '../views/BlogPost.vue'
import NotFound from '../views/NotFound.vue'

const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/blog',
name: 'BlogList',
component: BlogList
},
{
path: '/blog/:id',
name: 'BlogPost',
component: BlogPost,
props: true
},
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: NotFound
}
]

const router = createRouter({
history: createWebHistory(),
routes
})

export default router

Our BlogList component:

html
<!-- src/views/BlogList.vue -->
<template>
<div>
<h1>Blog Posts</h1>
<div v-if="loading">Loading...</div>
<div v-else>
<article v-for="post in posts" :key="post.id">
<h2>
<router-link :to="`/blog/${post.id}`">{{ post.title }}</router-link>
</h2>
<p>{{ post.excerpt }}</p>
</article>
</div>
</div>
</template>

<script>
export default {
name: 'BlogList',
data() {
return {
loading: true,
posts: []
}
},
created() {
// Simulating API call
setTimeout(() => {
this.posts = [
{ id: 1, title: 'Getting Started with Vue Router', excerpt: 'Learn the basics of Vue Router...' },
{ id: 2, title: 'Vue.js Components', excerpt: 'Understanding Vue components...' },
{ id: 3, title: 'State Management with Vuex', excerpt: 'Managing application state...' }
]
this.loading = false
}, 1000)
}
}
</script>

Our BlogPost component:

html
<!-- src/views/BlogPost.vue -->
<template>
<div>
<div v-if="loading">Loading post...</div>
<div v-else-if="error">{{ error }}</div>
<article v-else>
<h1>{{ post.title }}</h1>
<p class="meta">Posted on {{ post.date }}</p>
<div class="content">{{ post.content }}</div>
<router-link to="/blog">&larr; Back to all posts</router-link>
</article>
</div>
</template>

<script>
export default {
name: 'BlogPost',
props: ['id'],
data() {
return {
loading: true,
error: null,
post: null
}
},
created() {
this.fetchData()
},
methods: {
fetchData() {
this.loading = true
this.error = null

// Simulating API call
setTimeout(() => {
// In a real app, fetch from an API using this.id
if (this.id === '1') {
this.post = {
id: 1,
title: 'Getting Started with Vue Router',
date: 'January 15, 2023',
content: 'Vue Router is the official router for Vue.js. It deeply integrates with Vue.js core to make building Single Page Applications with Vue.js a breeze...'
}
this.loading = false
} else if (this.id === '2') {
this.post = {
id: 2,
title: 'Vue.js Components',
date: 'January 20, 2023',
content: 'Components are one of the most powerful features of Vue.js...'
}
this.loading = false
} else if (this.id === '3') {
this.post = {
id: 3,
title: 'State Management with Vuex',
date: 'January 25, 2023',
content: 'Vuex is a state management pattern + library for Vue.js applications...'
}
this.loading = false
} else {
this.error = 'Post not found!'
this.loading = false
}
}, 1000)
}
},
// Re-fetch data when params change
beforeRouteUpdate(to, from, next) {
this.id = to.params.id
this.fetchData()
next()
}
}
</script>

To better understand how Vue Router handles navigation, here's a diagram showing the flow:

Summary​

Vue Router is a powerful and flexible routing solution for Vue.js applications. In this introduction, we've covered:

  • Setting up Vue Router in a Vue.js application
  • Creating and configuring routes
  • Using <router-view> to render components
  • Creating navigation links with <router-link>
  • Working with dynamic routes and parameters
  • Implementing programmatic navigation
  • Creating nested routes for complex UIs
  • Using navigation guards to control access
  • Building a simple blog application with Vue Router

Vue Router offers much more than what we've covered here, including lazy-loading routes, scroll behavior customization, and transition effects. As you build more complex Vue applications, Vue Router will be an essential tool for creating intuitive user experiences.

Additional Resources​

Practice Exercises​

  1. Basic Navigation: Create a simple Vue application with three routes: Home, About, and Contact.

  2. Dynamic Routes: Extend the application by adding a Products section with dynamic routes for individual products.

  3. Route Guards: Add authentication to your application. Create a login page and protect certain routes so only authenticated users can access them.

  4. Nested Routes: Create a user dashboard with nested routes for profile, settings, and activity.

  5. 404 Page: Add a catch-all route to handle 404 errors when users navigate to non-existent routes.



If you spot any mistakes on this website, please let me know at feedback@compilenrun.com. I’d greatly appreciate your feedback! :)