Getting Started With Vue Router

Ed Zynda

Vue is already a great Javascript library that allows you to create some really cool, dynamic, front-end applications. Vue is also great for single page applications (SPA). SPAs work a little differently that your standard backend web application built in something like PHP. Instead of making requests to different routes on the backend and getting a fully rendered page as a response, a SPA does all the page rendering on the front-end and only sends requests to the server when new data is needed or needs to be refreshed or saved.

This can improve the responsiveness of your web application because you can render the pages once and display them dynamically based on the current context of the application. In order to make this work, you need a way to distinguish the different views or pages from eachother. In SPAs this is done with a router. Luckily Vue has a fully supported first-party router library called vue-router.

In this tutorial we'll setup a simple SPA that will show some information about popular cryptocurrencies. We'll call it "Crypto Info". It will have a few pages and link those pages using vue-router. You should already be familiar with Vue as well as creating and using Vue components. Having experience with .vue files is helpful but not required.

Setup

To get started, let's use the handy Vue command line installer. Open a terminal and run the following.

# install vue-cli
$ npm install --global vue-cli
# create a new project using the "webpack" template
$ vue init webpack router-app

When prompted, answer the questions displayed on the screen like so. Make sure to answer "yes" for installing vue-router.

 This will install Vue 2.x version of the template.

 For Vue 1.x use: vue init webpack#1.0 router-app

? Project name router-app <Enter>
? Project description A Vue.js project  <Enter>
? Author  <Enter>
? Vue build standalone  <Enter>
? Install vue-router? Yes
? Use ESLint to lint your code? No
? Setup unit tests with Karma + Mocha? No
? Setup e2e tests with Nightwatch? No

Once the app is setup, install all the dependencies and start up a dev server.

# install dependencies and go!
$ cd router-app
$ npm install
$ npm run dev

You should now be able to point a browser at http://localhost:8080 and see something like this.

Digging In

The great thing about the Vue command line tool is that it will wire up vue-router for us. To get a better understanding of how it works, we can take a look the boilerplate that was created. Open /src/router/index.js

import Vue from 'vue'
import Router from 'vue-router'
import Hello from '@/components/Hello'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Hello',
      component: Hello
    }
  ]
})

The first two lines are importing vue and vue-router. The third line is importing a component called Hello. We will discuss why in a bit. The @ is just a nice alias for the /src directory that was setup in webpack by the Vue command line tool.

Next we tell Vue to use the vue-router plugin. Finally the router is configured with a single route. The router uses Vue components as pages. In the above example we want to render the Hello component whenever a user navigates to the / route.

Next open /src/main.js

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  template: '<App/>',
  components: { App }
})

The first line is importing Vue again. The second line is bringing in a component called App. This will serve as the root component for the application. The third line is importing the router setup we looked at earlier. The next line tells Vue whether or not to show tips and warnings in the developer console of your browser. In this case it is set to false.

Finally a new Vue instance is created and mounted to the #app div in our html and then it instantiated the App component. We also inject the router configuration from earlier.

Now open /src/App.vue

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'app'
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

This, like I mentioned before, is the root component. It will serve as the point from which our page components will be rendered. Note that all the components we will use are in .vue files which allows us to save the template, javascript and styling into a single file.

Within the <template> tag we just have some simple markup. The important piece though is the <router-view> tag. The router uses this tag as a container for rendering the different components tied to the different routes. Just think of it as a placeholder.

The <script> tag just contains a simple Vue component object that does nothing. The <style> tag just contains some nice styling boilerplate provided by the Vue command line tool.

Now open /src/components/Hello.vue

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <h2>Essential Links</h2>
    <ul>
      <li><a href="https://vuejs.org" target="_blank">Core Docs</a></li>
      <li><a href="https://forum.vuejs.org" target="_blank">Forum</a></li>
      <li><a href="https://gitter.im/vuejs/vue" target="_blank">Gitter Chat</a></li>
      <li><a href="https://twitter.com/vuejs" target="_blank">Twitter</a></li>
      <br>
      <li><a href="http://vuejs-templates.github.io/webpack/" target="_blank">Docs for This Template</a></li>
    </ul>
    <h2>Ecosystem</h2>
    <ul>
      <li><a href="http://router.vuejs.org/" target="_blank">vue-router</a></li>
      <li><a href="http://vuex.vuejs.org/" target="_blank">vuex</a></li>
      <li><a href="http://vue-loader.vuejs.org/" target="_blank">vue-loader</a></li>
      <li><a href="https://github.com/vuejs/awesome-vue" target="_blank">awesome-vue</a></li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'hello',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
  font-weight: normal;
}

ul {
  list-style-type: none;
  padding: 0;
}

li {
  display: inline-block;
  margin: 0 10px;
}

a {
  color: #42b983;
}
</style>

This is very similar to the App component. Again, within the <template> tag there is the HTML markup for the component. In this case it's all the links and text shown when we pointed our browser to http://localhost:8080. This is because in our router config, we specified that / or the root path of our application should point to Hello.vue.

Now let's get rid of the default content and create a simpler home page. Edit Hello.vue to look like the following:

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
  </div>
</template>

<script>
  export default {
    name: 'Hello',
    data () {
      return {
        msg: 'Welcome to Crypto Info'
      }
    }
  }
</script>

If you reload, you should now see a page like this.

Creating and Linking to Routes

Now let's create a new page and add some links for navigating between the two. Open /src/router/index.js and edit it to look like the following.

import Vue from 'vue'
import Router from 'vue-router'
import Hello from '@/components/Hello'
import About from '@/components/About'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Hello',
      component: Hello
    },
    {
      path: '/about',
      name: 'About',
      component: About
    }
  ]
})

We've added a new route /about that points to a new component called About. We've also imported the new component at the top. We will create this shortly.

Now open /src/App.vue and edit the <template> section to look like this.

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <router-link :to="{ name: 'Hello' }">Home</router-link>
    <router-link to="/about">About</router-link>
    <router-view></router-view>
  </div>
</template>

As you can see, we added two <router-link> tags using two different methods. The router uses <router-link> to create html links to routes you created. The first method uses a named route. If you recall, in /src/router/index.js we added the name parameter to our routes. In this case the name of the route is Hello just like the component it points to. The second method is the standard method and just specifies the path we want to link to.

If you refresh the browser, you should see the original welcome page but with two links added.

If you click the About link, you will get a blank page. This is because we haven't created the component yet. Let's fix this be creating /src/components/About.vue.

<template>
  <div class="about">
    <h1>What is a Crypto-Currency?</h1>
    <p>
      It's a digital currency in which encryption techniques are used to regulate the generation of units of currency 
      and verify the transfer of funds, operating independently of a central bank.
    </p>
  </div>
</template>

<script>
export default {
  name: 'About'
}
</script>

Now if you refresh the browser and click About you should see the new page.

Dynamic Routes

So we can create a new page and a route to point to it but what about passing parameters? We'll need a page that displays some useful info about various crypto currencies based on a string id passed in the URL. Let's make that happen. Open /src/router/index.js again and add a third route.

...
import Coins from '@/components/Coins'

...

export default new Router({
  routes: [
    ...
   {
      path: '/coins/:id',
      name: 'Coins',
      component: Coins
    }
  ]
})

In order to display up-to-date information on the various currencies, we'll use the popular axios http client to fetch data from the free Coin Market Capitalization API. We'll accept a string parameter in the URL called :id. This will be passed to the API to retrieve the relevant data.

First we need to install axios.

npm install --save axios

Next create a file called /src/components/Coins.vue

<template>
  <div>
    <p>Name: {{ coin.name }}</p>
    <p>Symbol: {{ coin.symbol }}</p>
    <p>Price (USD): {{ coin.price_usd }}</p>
  </div>
</template>
<script>
  import axios from 'axios'

  export default {
    name: 'Coins',

    data() {
      return {
        coin: {}
      }
    },

    created() {
      this.fetchData()
    },

    watch: {
      '$route': 'fetchData'
    },

    methods: {
      fetchData() {
        axios.get('https://api.coinmarketcap.com/v1/ticker/'+this.$route.params.id+'/')
        .then((resp) => {
          this.coin = resp.data[0]
          console.log(resp)
        })
        .catch((err) => {
          console.log(err)
        })
      }
    }
  }
</script>

You'll notice that in the data object of our component, we declare an empty object called coin. This will store our coin information after it is fetched. In the <template> section we have some markup to display the name, symbol and US dollar price of the coin. The created method is a special hook used by Vue that is called before the component is rendered. In this case we are calling the fetchData method which is making a GET request with axios to the Coin Market Capitalization API and passing the :id parameter at the end.

We get the parameter from the $route object params property. This object is auto injected by VueRouter. The paramater we want is the :id parameter which we defined in our router file. On success, as defined in the the then promise method, we save the data returned into our coin object. This is then rendered on in the template.

One other thing we need is to add a watch hook for the $route object. VueRouter components are only rendered once for speed. If you need to rerender, you need to do that manually so in this case we want to rerender when the :id parameter in $route changes and then fetch new data.

Now lets create a few more links in /src/App.vue to see how this new page might be used.

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <router-link :to="{ name: 'Hello' }">Home</router-link>
    <router-link to="/about">About</router-link>
    <router-link to="/coins/ethereum">Ethereum</router-link>
    <router-link to="/coins/bitcoin">Bitcoin</router-link>
    <router-view></router-view>
  </div>
</template>

If you refresh the browser and click on Ethereum you should see something like this.

Now click on Bitcoin and you should see relevant information for that coin as well. If you want to try out other coins, have a look at https://api.coinmarketcap.com/v1/ticker/ and paste a few ids from the list into the URL of our app.

Conclusion

That's how easy it is to get started with Vue Router. There are a bunch of other great features as well and you can read about them in the official documentation. I hope this tutorial is enough to get you started making some cool SPAs in Vue!

Ed Zynda

Ed is a nine year Air Force veteran and web software engineer with a passion for what makes the Internet tick.