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
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
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
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')
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
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
}
To add more, you just need to add more to the object - so below I've added 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
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')
}
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
.
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'
}
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' }
}
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
}
}
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>
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'),
}]
}
]
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 | | |
| | └ - - - - - - - ┘ └ - - - - - ┘ | |
| └ - - - - - - - - - - - - - - - - ┘ |
└ - - - - - - - - - - - - - - - - - - ┘
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!
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')
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 }})
Similarly, the same Javascript could be represented in HTML as so:
<router-link to="{ name: 'About', query: { id : 15 }}">About</router-link>
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 }})
Or in HTML, append the replace
attribute:
<router-link to="{ name: 'About', query: { id : 15 }}" replace>About</router-link>
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.
Also Published Here