Be insensitive, and keep a lifelong growth mindset.

0%

Build Web App with Vue.js

1. Installing Vue.js

3 ways to install Vue.js

  • CDN(Content Delivery Network):
  • NPM(Node Package Manager):
    • npm install vue
    • sudo npm install –global vue-cli
  • Visit nodejs.org and download an installer

Start a New Project

1
2
vue init webpack compare-vue
//webpack is the template name, and compare-vue is the project name.

Project Configuration
Project Configuration

CD into the project folder and run npm install to generate packages and jsons.

1
2
cd compare-vue
npm install

Run a project

1
npm run dev

2. Vue Components

index.html
Start point of the project, everything of the app will be inside the div with id “app”

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>compare-vue</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

src/main.js
Imports and new Vue project start.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 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 }
})

App.vue
The entry point of the app, including html, script and style

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<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>

src/router/index.js
Define the paths of the project.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
},
]
})

3. Integrating a CSS Framework

Install bulma in the project folder (compare-vue)

1
npm install bulma --save

Then import bulma in App.vue. To support sass, we have to add ‘lang=”sass”‘ in style tag, and also delete these “;” and “{}” under style tag.

1
2
3
4
5
6
7
8
9
10
11
12
<style lang="sass">
@import '../node_modules/bulma/bulma.sass'

#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>

Install additional packages to fully support sass.

1
npm install node-sass sass-loader style-loader --save-dev

Create mq.sass file under src folder with the following contents.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
$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

Then import ‘mq’ in App.vue.

1
2
3
4
5
6
7
8
9
10
11
12
13
<style lang="sass">
@import '../node_modules/bulma/bulma.sass'
@import 'mq'

#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>

Import mq in Home.vue and Faq.vue as well.

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

4. Vue.js Navigation

Go to bulma-Doc-Navbar to see the nav bar template.

Include Font Awesome in the project index.html.

1
2
3
4
5
6
7
...
<head>
<meta charset="utf-8">
<title>compare-vue</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
...

Then edit App.vue template tag section as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

<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">
<span></span>
<span></span>
<span></span>
</span>

<div class="nav-right nav-menu">
<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>
</div>
</template>

Edit the App.vue style tag section as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<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

</style>

5. Making the Navigation Function

Add v-on:click attribute to nav-toggle and v-bind to both nav-toggle and nav-menu as follows:

1
2
3
4
5
6
7
8
9
...
<span class="nav-toggle" v-on:click="toggleNav" v-bind:class="{ 'is-active': isActive }">
...
</span>
...
<div class="nav-right nav-menu" v-bind:class="{ 'is-active': isActive }">
...
</div>
...

Edit the App.vue script tag content as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
export default {
name: 'app',
data: function() {
return {
isActive: false
}
},
methods: {
toggleNav: function() {
this.isActive = !this.isActive;
}
}
}
</script>

Add sass item in App.vue style section:

1
2
3
4
...
.nav-toggle span
background-color: #F1F1F1
...

Add footer under router-view in App.vue template

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
...
<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>
...

Add styling for footer in App.vue style content

1
2
3
4
5
6
7
8
9
...
footer
background-color: $primary !important
color: #fff

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

7. Hero Section

Go to bulma-Doc-Hero to see the hero template.

Edit the template tag section in Home.vue as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<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>
</div>
</template>

Edit the script tag section to return the heading and subheading attributes as follows:

1
2
3
4
5
6
7
8
9
10
11
<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>

To add the background, firstly we need to add the clouds.jpg to src/assets folder.

Then add the sass stylings in Home.vue style tag section as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!-- Add "scoped" attribute to limit CSS to this component only -->
<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
</style>

Now the home page looks much better!
Home Page

8. Supporting Content

Add a new section below the “hero” section in Home.vue template tag section.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<template>
...
<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.</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>

Then add additional css styling in Home.vue style tag section.

1
2
3
4
5
6
7
8
9
10
.fa-cog
font-size: 40px

#learn
+desktop
margin-bottom: 2rem

.pd
+tablet
padding: 2em 0

9. FAQ Page

Install axios with the following command. (Axios is a promise based HTTP client for the browser and node.js)

1
npm install axios --save

Edit the script tag section in FAQ.vue as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import axios from 'axios';

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

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

Then edit the template tag section in FAQ.vue as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<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 the FAQ page will be look like this.
FAQ page