In this post you will be able to see how to create entire new Vue project and how to properly install and create Vue Router in order to make SPA (single-page application). As a first step download and install the latest version of Node.js from Node Js Website. Beside this, we should install vue-cli (Vue command line interface). The main reason for installing vue-cli is to help us install Vue project templates.
Installation
To perform vue-cli installation, write this line in your terminal:
npm install -g vue-cli
After we installed vue-cli we can initialize vue project with following templates:
- webpack
- webpack-simple
- browserify
- browserify-simple
- pwa
- simple
Among this six templates, everyone should be able to find suitable one. For more details about Vue templates and their features, visit this website.
In this blog post we will use webpack-simple template:
vue init webpack-simple my-vue-project
After a while you'll be prompt to answer several questions:
? Project name (my-vue-project) // name for your further project
? Project description (A Vue.js description) // descripe your project
? Author // author name
? Lincence (MIT) // enter
? Use sass (y/N) // press enter for default answer (in this case SASS won't be used)
After setting up basic project properties, few lines below you will see that vue-cli generated new project inside folder called my-vue-project
. Down there we will get few more instructions on what to do in order to successfully finish project installation.
cd my-vue-project
npm install
npm run dev
Basics
As a result, browser will start "Welcome page". Now, we can open our project from any text editor - IDE (in my case it's PHP storm). Inside src
folder, there are two files which will be interesting for our future development.
main.js
- inside this file vue-cli automatically created VueJS objectApp.js
- in this file we have code responsible for rendering "Welcome Page"
Feel free to remove entire code, from App.js
in order to start from scratch. As a result, we'll get blank page in our browser.
Also it is very important to wrap whole HTML code into one (root) HTML element, otherwise our Vue component won't work.
Let's start with simple example:
<template>
<div>
<p>HELLO FROM App.js TEMPLATE</p>
</div>
</template>
Vue Router installation
Open terminal, and navigate to project folder. Then write following line:
npm install vue-router
There is a few ways to install Vue Router but this is the most common one. For more details about installation visit this page.
To check weather we successfully installed vue-router, open package.json
file from project directory. In the dependencies
object you have to have vue-router
property.
Defining Routes
In main.js
file import VueRouter object from vue-router
package, and make sure that Vue object is going to use it in the right way.
import VueRouter from 'vue-router';
Vue.use(VueRouter);
Inisde src
folder, create new folder - routes
. Than in routes folder create new file routes.js
.
import Home from '../components/Home.vue';
import Users from '../components/Users.vue';
import Details from '../components/Details.vue';
export const routes = [
{path: '/', component: Home},
{path: '/users', component: Users},
{path: '/details', component: Details}
];
When we visit url http://localhost:8080
, router will call Home.vue
component defined in routes
variable. Similar will happen if we visit http://localhost:8080/users
, router will call Users.vue
. Exactly the same will happen with Details.vue
component.
Than, go back to main.js
and import const routes
from routes.js
, which will be used in VueRouter
object. At the end, entire main.js
file will have following structure:
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router';
import {routes} from './routes/routes.js';
Vue.use(VueRouter);
const router = new VueRouter({
mode: 'history',
routes
});
new Vue({
el: '#app',
router,
render: h => h(App)
});
To make router work we will need to modify App.js
file and add router-view
component.
<template>
<div>
<router-view></router-view>
</div>
</template>
This component gives us ability to wrap another component inside, and display its content on the page.
There is another crucial component which also plays vital role in SPA applications. Its name isrouter-link
. This component, allows us to move between different pages.
<template>
<div>
<p>HELLO FROM HOME PAGE</p>
<router-link to="/users" tag="button" class="btn btn-primary" style="color: black;">
button
</router-link>
</div>
</template>
As you see router-link
can have attributes which help us to determine more closely content inside tag. For instance, make some styling, add class or id. Within help tag
attribute, we define, type of HTML element. Nevertheless, from my point of view, key role plays to
attribute, which main task is to properly navigate us to another page. In case above, we will get button
HTML element. As a result, if we click on that button, we will be redirect to Users
page. We can also give a name to our route, but we have to do some changes inside routes.js
file. For that matter, to
have to be an object.
export const routes = [
{path: '/', component: Home, name: 'home'},
{path: '/users', component: Users, name: 'users'},
{path: '/details', component: Details, name: 'details'}
];
<template>
<div>
<p>HELLO FROM HOME PAGE</p>
<router-link :to="{name: 'users'}" tag="button" class="btn btn-primary" style="color: black;">
button
</router-link>
</div>
</template>
Parameters and Queries
<template>
<div>
<p>HELLO FROM USER PAGE</p>
<ul class="list-group">
<router-link :to="{name: 'details', params: {id: 1}}" tag="li" class="list-group-item">User 1</router-link>
<router-link :to="{name: 'details', params: {id: 2}}" tag="li" class="list-group-item">User 2</router-link>
<router-link :to="{name: 'details', params: {id: 3}}" tag="li" class="list-group-item">User 3</router-link>
</ul>
</div>
</template>
We got a list of three users. Each of them is created inside router-link
, and links to Details page. You already noticed that to
attribute has name
property that chooses path by name, and params
property which is another nested object with id property. Before we decide to click on one of them, you must define id
in routes.js
.
import Home from '../components/Home.vue';
import Users from '../components/Users.vue';
import Details from '../components/Details.vue';
export const routes = [
{path: '/', component: Home},
{path: '/users', component: Users, name: 'users'},
{path: '/users/:id', component: Details, name: 'details'}
];
<template>
<p>HELLO FROM DETAILS PAGE</p>
<div>
<p>{{ id }}</p>
<router-link to="/users" tag="button">Back to user page</router-link>
</div>
</template>
<script>
export default {
data() {
return {
id: this.$route.params.id
}
}
}
</script>
It is important to know that there is possibility to pass query parameters too. It can be quite useful feature. Let's do some example:
<template>
<div>
<p>HELLO FROM USER PAGE</p>
<ul class="list-group">
<router-link :to="{name: 'details', params: {id: 1}}" tag="li" class="list-group-item">User 1</router-link>
<router-link :to="{name: 'details', params: {id: 2}}" tag="li" class="list-group-item">User 2</router-link>
<router-link :to="{name: 'details', params: {id: 3}, query: {country:'England', city: 'London'}}" tag="li" class="list-group-item">User 3</router-link>
</ul>
</div>
</template>
We have to set query
as object property, which has another object as value. It is standard form for passing queries through url.
If you clicked on one of users
from the list, you will be navigated to Details
page.
Nested Routes
At this point, I would like to show you one more great feature called Nested routes, which I believe you will need to use very often in order to make complex page structure. Let's start to modifying our routes:
import Home from '../components/Home.vue';
import Users from '../components/Users.vue';
import Details from '../components/Details.vue';
import Edit from '../components/Edit.vue';
export const routes = [
{path: '/', component: Home},
{path: '/users', component: Users, name: 'users'},
{
path: '/users/:id', component: Details, name: 'details', children: [
{path: '/edit', component: Edit, name: 'edit'}
]
}
];
We added children
property to one of our routes. Now we must make some changes inside Detail.vue
component. We will add new <router-link>
and <router-view>
.
<template>
<div>
<p>HELLO FROM DETAILS PAGE</p>
<p>{{ id }}</p>
<router-link :to="{name: 'edit'}" tag="button">Edit this user</router-link>
<router-link to="/users" tag="button">Back to user page</router-link>
<router-view></router-view>
</div>
</template>
In this case <router-view>
inside Details.vue
component is an entry point for Edit.vue
component. In other words Edit.vue
component will be loaded within Details.vue
component, below "Edit this user" and "Back to user page" buttons.
Navigation Guards
This example will represent one nice feature provided by Vue Router - Navigation Guards. Let's assume that we want to edit some information about user. For that operation we need to have certain permission. It is not clever idea to enable anyone to visit that page, without meeting certain condition. For that purpose one of the security meassure, can be Navigation Guards, which will force user to load page only if some condition is satisfied. For instance, checking previous path inside URL.
import Home from '../components/Home.vue';
import Users from '../components/Users.vue';
import Details from '../components/Details.vue';
import Edit from '../components/Edit.vue';
export const routes = [
{path: '/', component: Home},
{path: '/users', component: Users, name: 'users'},
{
path: '/users/:id', component: Details, name: 'details', children: [
{
path: '/edit', component: Edit, name: 'edit', beforeEnter(from, to, next) {
console.log(to); // Take a look what you can find in this object
console.log(from); // Take a look what you can find in this object
if (to.name === 'details') {
// If previous page had path ..../details
next(); // next() is called and allow us to visit another page
} else {
// Otherwise, our journy will be stoped.
console.log('You can not access to this page');
}
}
}
]
}
];
There are three places, where we can define is user allowed to visit certain page. First one is inside main.js
, where we use router.beforeEach((to, from, next) => {})
, and check every page change. The most common case is when we define beforeEnter((to, from, next) => {}))
inside route object. At last we can define guards inside component, using beforeRouterEnter((to, from, next) => {})
. In that case, beforeRouterEnter
function is invoked inside life cycle hook.
<template>
<div>
<p>HELLO FROM DETAILS PAGE</p>
<p>{{id}}</p>
<router-link :to="{name: 'edit'}" tag="button">Edit this user</router-link>
<router-link to="/users" tag="button">Back to user page</router-link>
<router-view></router-view>
</div>
</template>
<script>
export default {
data() {
return {
id: this.$route.params.id
}
},
beforeRouteLeave(to, from, next) {
console.log(to);
console.log(from);
next();
}
}
</script>
More information about Navigation guards, you can find on this website.
Router Redirect
At the end, I would like to show you one more crucial feature, which you will use quite often. User can pass anything through URL, and sometimes it is not matched with our routes. In that case we can define special path with asterisk ( * ) and it will handle all non-define routes.
import Home from '../components/Home.vue';
import Users from '../components/Users.vue';
import Details from '../components/Details.vue';
import Edit from '../components/Edit.vue';
export const routes = [
{path: '/', component: Home},
{path: '/users', component: Users, name: 'users'},
{
path: '/users/:id', component: Details, name: 'details', children: [
{
path: '/edit', component: Edit, name: 'edit', beforeEnter(from, to, next) {
console.log(to); // Take a look what you can find in this object
console.log(from); // Take a look what you can find in this object
if (to.name === 'details') {
// If previous page had path ..../details
next(); // next() is called and allow us to visit another page
} else {
// Otherwise, our journy will be stoped.
console.log('You can not access to this page');
}
}
}
]
},
// This line is added
{path: '*', redirect: '/users'}
];
Then try to enter anything you want into URL, and you will be redirect to Users.vue
component, and URL will look like http://localhost:8080/users
.
Conclude
Vue Router is one of the core VueJs features, and it can significantly improve our application. Also there are many other great features and all about them you can find on this website.