Create your account

Already have an account? Login here

Note: By joining, you will receive periodic emails from Coursetro. You can unsubscribe from these emails.

Create account

Build your First Vue.js App | Vue.js 2.0 Tutorial

By Gary simon - May 28, 2017

Note:
This tutorial is a part of our free course React vs Angular vs Vue.js by Example. Check it out and join in from the beginning!

Vue.js is a fast, popular javascript framework for building user interfaces. In the MVC model, it handles the View. It can be used in conjunction with other javascript libraries, or used alone to build SPA's (Single Page Applications).

In this tutorial, I'm going to make the assumption that you know:

  • HTML & CSS
  • Basic Javascript

And I'm also going to make the assumption that you've never touched Vue.js. So, if you're ready to build your first Vue.js app, let's get started!

Maybe you prefer watching a video instead?

Everything you're about to read is available in a video tutorial format below. Be sure to Subscribe to the Official Coursetro Youtube Channel for more awesome videos.

Install the Vue.js Project

Prior to this tutorial, I wrote a tutorial that shows you how to install a vue.js project. Please refer to that tutorial first to get the project up and running. 

Note: This process is covered at the beginning of the video above.

Integrating the Bulma CSS Framework

Bulma is a relatively new responsive flexbox-based framework. You can just as easily use other alternatives, like Bootstrap or Foundation for this process.

Once you have generated a new Vue.js project with the Vue CLI, in the console within the project folder type:

> npm install bulma --save

This will download the bulma package and add it to the node_modules folder. 

Next, we have to let Vue know that we want to use Bulma along with Sass. Within the /src/App.vue file near the bottom at the style section, change it to:

<style lang="sass">
@import '../node_modules/bulma/bulma.sass'
@import 'mq'

</style>

We've added a lang attribute with the sass preprocessor. We're using Sass as that's what Bulma comes packaged with. It also comes with a standard CSS version within the node_modules folder if you prefer to work that way.

Then, we're importing bulma.sass, and another mq file that does not yet exist.  Let's create that file real quickly.

In the same folder /src create a new file called mq.sass: and copy / paste this Sass:

$primary: #1EC9AC !default

// Responsiveness
// 960, 1152, and 1344 have been chosen because they are divisible by both 12 and 16
$tablet: 769px !default
// 960px container + 40px
$desktop: 1000px !default
// 1152px container + 40
$widescreen: 1192px !default
// 1344px container + 40
$fullhd: 1384px !default

=mobile
  @media screen and (max-width: $tablet - 1px)
    @content

=tablet
  @media screen and (min-width: $tablet), print
    @content

=tablet-only
  @media screen and (min-width: $tablet) and (max-width: $desktop - 1px)
    @content

=desktop
  @media screen and (min-width: $desktop)
    @content

=desktop-only
  @media screen and (min-width: $desktop) and (max-width: $widescreen - 1px)
    @content

These are some variables and mixins that we're going to use in our custom Sass styling once we get to that stage.

Bulma also uses FontAwesome for icons. So we need to import that within the /index.html file:

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">

This goes just before the closing </head> tag.

Vue Components

Now we're now ready to start working with the components.

Components in Vue are reusable elements that contain a template (HTML), logic through javascript, and styling via CSS or Sass, depending on your preferences.

The layout / UI of the project will ultimately determine how your components are structured. For instance, the project that we're going to build is based on a mockup that we created within Adobe XD:

  • The red line signifies the main App.vue component, which will contain the items that will always remain present in the UI. That includes the navigation up top, and the footer at the bottom.
  • The blue line represents the components that will change based on the current page. We only designed a mockup for the home page and a FAQ page. So, we will have 2 additional components for Home and FAQ. 

When we use the Vue CLI to generate a project, we chose yes when prompted whether or not we want to integrate the Vue router. The vue router will be placed between the navigation HTML and the footer HTML with: <router-view></router-view>.

Defining the Navigation and Footer

Now, we're going to work within the /src/App.vue to designate the HTML and Sass necessary for the navigation bar and the footer.

In the top <template> section, paste the following HTML:

<template>
  <div id="app">
    <div class="nav has-shadow">
      <div class="container">
        <div class="nav-left">
          <a class="nav-item">MyCompany</a>
        </div>

        <span class="nav-toggle" v-on:click="toggleNav" v-bind:class="{ 'is-active': isActive }">
          <span></span>
          <span></span>
          <span></span>
        </span>

        <div class="nav-right nav-menu" v-bind:class="{ 'is-active': isActive }">

          <router-link to="/" class="nav-item r-item">Home</router-link>
          <router-link to="faq" class="nav-item r-item">Features</router-link>
          <router-link to="faq" class="nav-item r-item">About</router-link>
          <router-link to="faq" class="nav-item r-item">FAQ</router-link>

          <div class="nav-item">
            <p class="control">
              <a class="button is-primary is-outlined">
                <span class="icon">
                  <i class="fa fa-download"></i>
                </span>
                <span>Join Now</span>
              </a>
            </p>
          </div>

        </div>
      </div>
    </div>

    <router-view></router-view>

    <footer class="footer is-primary">
      <div class="container">
        <div class="columns">
          <div class="column">
            <p>And this right here is a spiffy footer, where you can put stuff.</p>
          </div>
          <div class="column has-text-right">
            <a class="icon" href="#"><i class="fa fa-facebook"></i></a>
            <a class="icon" href="#"><i class="fa fa-twitter"></i></a>
          </div>
        </div>
      </div>
    </footer>
  </div>
</template>

I know, it's rather lengthy, but it will get the job done. Many of the classes here are defined within Bulma. Check out the Bulma Documentation for more information.

You may also notice we've added something called v-on and v-bind. These are Vue directives.

  • v-on:click is figured when a user clicks the element it's attached to. It's bound to a custom method called toggleNav that we will define in a little bit.
  • v-bind:class is a directive for 2-way data binding. You can also specify the style attribute. It's bound to: { 'is-active': isActive }. This means that the class of is-active (which comes from Bulma) will be added to this element if the property of isActive is true

    When a user clicks on this hamburger icon menu, toggleNav will be called and we will toggle isActive between true and false. When this happens, v-bind will attach or detach the is-active class.

Now, let's work in the <script> section of App.vue:

<script>
export default {
  name: 'app',
  data: function() {
    return {
      isActive: false
    }
  },
  methods: {
    toggleNav: function() {
      this.isActive = !this.isActive;
    }
  }
}
</script>

We've added a data and methods property. These are necessary to ensure that our responsive navigation works on mobile when a user clicks on a hamburger icon menu. We're simply defining a property of isActive and toggling between true and false within the toggleNav method.

The third and final section of our App.vue is the style section. Change it to:

<style lang="sass">
@import '../node_modules/bulma/bulma.sass'
@import 'mq'

.nav
  background-color: #383838
  a:hover
    color: gray

.nav-left a 
  color: #fff
  font-weight: bold

a.r-item
  color:#C1C1C1
  padding: 0.5rem 1.75rem
  +mobile
    color: gray
    &:hover
      background-color: #F1F1F1

.nav-toggle span
  background-color: #C1C1C1

footer
  background-color: $primary !important
  color: #fff

  .icon
    color: #fff
    margin-left: 20px

</style>

Save the file and run npm run dev in the console at the project folder. Your app should now have a top navbar and a bottom footer.

The Home Component

Next, we have to structure our first component which will show the home page content of our landing page.

Within the /src/components folder, rename the default generated Hello.vue to Home.vue and make the following changes:

<template>
  <div class="home">

  </div>
</template>

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

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style lang="sass" scoped>
@import '../mq'

</style>

 Great. Now, at the top, paste the following to replace the <template> section:

<template>
  <div class="home">
    <section class="hero">
      <div class="hero-body">
        <div class="container">
          <h1 class="title">{{ heading }}</h1>
          <div class="is-two-thirds column is-paddingless">
            <h2 class="subtitle is-4">{{ subheading }}</h2>
          </div>
          <a class="button is-large is-primary" id="learn">Learn more</a>
        </div>
      </div>
    </section>

    <section class="section">
      <div class="container">
        <div class="columns pd is-desktop">
          <div class="column is-1 has-text-centered">
            <i class="fa fa-cog is-primary"></i>
          </div>
          <div class="column is-one-third-desktop">
            <p class="title"><strong>We provide superior logistics so that your business can succeed in a crazy world.</strong></p>
          </div>
          <div class="column">
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.</strong></p>
          </div>
        </div>
      </div>

      <div class="columns pd">
        <div class="column">
          <div class="card">
            <div class="card-content">
              <p class="title">"I think it's an absolutely excellent tool for our business. I can't survive without this thing."</p>
              <p class="subtitle">- Gary Simon</p>
            </div>
          </div>
        </div>
        <div class="column">
          <div class="card">
            <div class="card-content">
              <p class="title">"I think it's an absolutely excellent tool for our business. I can't survive without this thing."</p>
              <p class="subtitle">- Gary Simon</p>
            </div>
          </div>
        </div>
        <div class="column">
          <div class="card">
            <div class="card-content">
              <p class="title">"I think it's an absolutely excellent tool for our business. I can't survive without this thing."</p>
              <p class="subtitle">- Gary Simon</p>
            </div>
          </div>
        </div>
      </div>
    </section>
  </div>
</template>

Nothing interesting is happening here, aside from the interpolation brackets for the heading and subheading. Interpolation brackets are the {{ heading }} section of the code. heading and subheading are properties (like variables) that we will define in the component script section.

I'm using them just to show you how to display data that's defined in the component logic.

Now, in the <script> section, paste:

<script>
export default {
  name: 'home',
  data () {
    return {
      heading: 'Soaring to new heights',
      subheading: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'
    }
  }
}
</script>

Simple enough! We add data and define our two properties.

Paste the following into the <style> section:

<style lang="sass" scoped>
@import '../mq'

.hero
  background: url('../assets/clouds.jpg')
  background-size: cover

  .title
    +mobile
      font-weight: bold
    +tablet
      font-size: 2.5rem
    +desktop
      font-size: 4rem
      margin-top: 2rem

h2
  margin: 1.5rem 0 2rem 0 !important

.fa-cog
  font-size: 40px

#learn
  +desktop
    margin-bottom: 2rem

.pd
  +tablet
    padding: 2em 0

</style>

You also need to place an asset called clouds.jpg within the /src/assets folder. If you want access to this asset, simply visit the course page: React vs Angular vs Vue.js by Example and login to your account. There is a project file download button located on the course page that will have the clouds.jpg file.

Awesome. This component is now finished.

The FAQ Component

We designed a FAQ page in our Adobe XD mockup process, so let's create that here in Vue.js.

Create a new component within /src/components/ called Faq.vue and get it started with the following code:

<template>
  <div class="faq">

  </div>
</template>

<script>

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

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style lang="sass" scoped>
@import '../mq'


</style>

In the <template> section, paste the following:

<template>
  <div class="faq">
    <div class="container">
      <section class="section">
        <h1 class="title">FAQ</h1>
        <h2 class="subtitle is-4">Lorum ipsum and all of that jazz.</h2>

        <div class="columns" v-if="faqs && faqs.length">
          <div class="column is-one-third" v-for="faq of faqs">
            <div class="card">
              <div class="card-content">
                <p class="title">{{ faq.title }}</p>
                <p class="answer">{{ faq.body }}</p>
              </div>
            </div>
          </div>
        </div>
      </section>
    </div>
  </div>
</template>

Now we have something new! A v-if directive and a v-for directive. 

The if is simple enough: If a property called faqs exists AND it actually contains results, then show whatever is nested within the element I'm attached to.

The for allows you to iterate through an array, or an array of objects. We use interpolation to call upon the specific properties that are a part of that object via {{ faq.title }}.

To make this project more interesting, we need to install Axios which is an HTTP client library. It will allow us to connect to an API to fetch data to popular our FAQ page.

Visit the console in the project folder and type:

> npm install axios --save

Next, in the <script> section of Faq.vue, add:

<script>
import axios from 'axios';

export default {
  name: 'faq',
  data: () => ({
    faqs: [],
    errors: []
  }),

  created() {
    axios.get('http://jsonplaceholder.typicode.com/posts')
      .then(response => {
        this.faqs = response.data.slice(0,10);
      })
      .catch(e => {
        this.errors.push(e)
      })
  }
}
</script>

We first import axios so we can use it.

Then we define two properties as arrays within the data section.

Then we call the created() method, which is fired when the component loads. Within it, we use axios.get to get the results from a public API. I'm also using .slice to limit the results to 10.

Finally, in the <style> section, add:

<style lang="sass" scoped>
@import '../mq'

.pd
  padding: 2.5em 0 1.5em 0

.answer
  margin-top: 10px !important
  color: gray

.columns
  flex-wrap: wrap

</style>

Setup the Routes 

One final step is to visit the /src/router/index.js file to define our routes for the home and faq page:

import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home'
import Faq from '@/components/Faq'

Vue.use(Router)

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

Simple enough. We import both Home and Faq vue components, and then we add each as objects that contain properties that define the path's, names and components they're associated with.

Run it!

Now, run npm run dev in the console and the project should work!

Hopefully you were able to learn a lot about Vue and this fairly straightforward framework. 

Note:
This tutorial is a part of our free course React vs Angular vs Vue.js by Example. Check it out and join in from the beginning!


Share this post




Say something about this awesome post!