Vue Router example – with Nav Bar, Dynamic Route & Nested Routes
Vue Router deeply integrates with Vue.js that we can use to build single-page Vue Application in simple way. In this tutorial, we’re gonna look at a Vue Router example that allows us to navigate among tabs and dynamically show item details from a item list with Nav bar, Dynamic Route and Nested Routes.
More Practice:
– Spring Boot + Vue.js example | Spring Data JPA + REST + PostgreSQL CRUD
– Spring Boot + Vue.js example | Spring Data JPA + REST + MySQL CRUD
Vue Router example Overview
Goal
We can:
– click on Nav Bar button to change view among Pages.
– click on any Customer to show details.
Demo
Vue Router
When adding Vue Router to Vue App, we have 2 core actions:
– map components to the routes
– let Vue Router know where to render them
Add Vue Router to Project
– Run command: npm install vue-router
.
– Import router
to main.js:
import Vue from "vue"; import App from "./App.vue"; import router from './router' Vue.config.productionTip = false; new Vue({ router, // inject the router to make whole app router-aware render: h => h(App) }).$mount("#app");
Vue Router with Nav Bar
– Define some routes, each route has a path
and maps to a component
:
src/router.js
import Vue from "vue"; import Router from "vue-router"; import CustomersList from "./components/CustomersList.vue"; import AddCustomer from "./components/AddCustomer.vue"; import SearchCustomers from "./components/SearchCustomers.vue"; Vue.use(Router); export default new Router({ // get rid of the hash (#) in Url // the hash (#) helps the page not to be reloaded when the URL changes mode: "history", routes: [ { path: "/", name: "customers", alias: "/customer", // go '/', the URL remains '/', but it wcill be matched if visiting '/customer' component: CustomersList }, { path: "/add", name: "add", component: AddCustomer }, { path: "/search", name: "search", component: SearchCustomers } ] });
src/App.vue
<template> <div id="app"> <nav> <router-link to="/">Customers</router-link> <router-link to="/add">Add</router-link> <router-link to="/search">Search</router-link> </nav> <router-view/> </div> </template>
– We use router-link
component for navigation and specify the link with ‘to’ prop. By default, <router-link>
will be rendered as an <a>
tag.
– router-view
is the router outlet that render the matched component.
Vue Router with Dynamic Route
For mapping routes with the given pattern to the same component:
With path: "/customer/:id"
, urls like /customer/1
and /customer/42
will both map to the same route:
router.js
const router = new VueRouter({ routes: [ { path: "/customer/:id", name: "customer-details", component: Customer } ] });
When a route is matched, the value of the dynamic segments will be exposed as this.$route.params
in every component. Therefore, we can render the current id with this.$route.params.id
:
Customer.vue
<template> <div> [id: {{ this.$route.params.id }} - name: {{ this.$route.params.name }}] </div> </template> <script> export default { name: "customer" }; </script>
Vue Router with Nested Routes
To render components into another one, we need to use the children
option in Vue Router constructor config:
router.js
export default new Router({ routes: [ { path: "/", name: "customers", component: CustomersList, children: [ { path: "/customer/:id", name: "customer-details", component: Customer } ] } ] });
Then add the child component inside the parent component’s template:
CustomersList.vue
<template> <div> <ul> <li v-for="(customer, index) in customers" :key="index"> <router-link :to="{name: 'customer-details', params: { name: customer.name, id: index + 1 }}"> {{customer.name}} </router-link> </li> </ul> <router-view></router-view> </div> </template>
We use Named Route name: 'customer-details'
to make link to component, and we can also pass an object ({name, id})
to the router-link
component:
Customer ABC
Project Structure
We have:
– Components: CustomersList
, AddCustomer
, SearchCustomers
are corresponding to 3 Navbar buttons: Customers, Add, Search.
– Customer
components is the child of CustomersList
component, its UI view is embeded into parent component using <router-view>
tag.
– App.vue
contains the whole application template with Nav bar and <router-view>
.
– We define routes, each route has a path and maps to a component in router.js
.
– main.js
mount App component with router to be injected.
Practice
Technologies
– Vue CLI 3.0.1
– Vue 2.5.17
– Vue Router 3.0.1
Setup Vue Project
Install vue-cli
For use Vue CLI anywhere, run command:
npm install -g vue-cli
Init Project
Point cmd to the folder you want to save Project folder, run command:
npm create vue-router-example
You will see 2 options, choose default:
Add Vue Router to Project
– Run command: npm install vue-router
.
– Import router
to main.js:
import Vue from "vue"; import App from "./App.vue"; import router from './router' Vue.config.productionTip = false; new Vue({ router, // inject the router to make whole app router-aware render: h => h(App) }).$mount("#app");
Define Routes
src/router.js:
import Vue from "vue"; import Router from "vue-router"; import CustomersList from "./components/CustomersList.vue"; import AddCustomer from "./components/AddCustomer.vue"; import SearchCustomers from "./components/SearchCustomers.vue"; import Customer from "./components/Customer.vue"; Vue.use(Router); export default new Router({ mode: "history", routes: [ { path: "/", name: "customers", alias: "/customer", component: CustomersList, children: [ { path: "/customer/:id", name: "customer-details", component: Customer } ] }, { path: "/add", name: "add", component: AddCustomer }, { path: "/search", name: "search", component: SearchCustomers } ] });
App template with Navbar and router-view
src/App.vue:
<template> <div id="app" class="container-fluid"> <div class="site-info"> <h1>ozenero</h1> <h3>Router example</h3> </div> <nav> <router-link class="btn btn-primary" to="/">Customers</router-link> <router-link class="btn btn-primary" to="/add">Add</router-link> <router-link class="btn btn-primary" to="/search">Search</router-link> </nav> <br/> <router-view/> </div> </template> <script> export default { name: "app" }; </script> <style> .site-info { color: blue; margin-bottom: 20px; } .btn-primary { margin-right: 5px; } .container-fluid { text-align: center; } </style>
Mock Components
components/AddCustomer.vue:
<template> <div> <h4>Add Customer page</h4> <p>[under construction...]</p> </div> </template> </pre> <em>components/SearchCustomers.vue</em>: <pre class="lang:xhtml"> <template> <div> <h4>Search Customers Page</h4> <p>[under construction...]</p> </div> </template>
Components with Dynamic Route & Nested Routes
Parent Component
components/CustomersList.vue:
<template> <div class="list row"> <div class="col-md-6"> <h4>Customers List</h4> <ul> <li v-for="(customer, index) in customers" :key="index"> <router-link :to="{ name: 'customer-details', params: { name: customer.name, id: index + 1 } }"> {{customer.name}} </router-link> </li> </ul> </div> <div class="col-md-6"> <router-view></router-view> </div> </div> </template> <script> export default { name: "customers-list", data() { return { customers: [ { name: "Jack Smith" }, { name: "Adam Johnson" }, { name: "Katherin Watson" } ] }; } }; </script> <style> .list { text-align: left; max-width: 500px; margin: auto; } </style>
Child Component
components/CustomersList.vue:
<template> <div v-if="this.$route.params.name"> <h4>Customer</h4> [id: {{ this.$route.params.id }} - name: {{ this.$route.params.name }}] </div> <div v-else> <br/> <p>Please click on a Customer...</p> </div> </template> <script> export default { name: "customer" }; </script>