DEV Community

Cover image for Vue.js Tutorial: build a functional SPA from scratch
Hunter Johnson for Educative

Posted on • Originally published at educative.io

Vue.js Tutorial: build a functional SPA from scratch

A front-end framework helps developers create modern web applications called single-page apps (SPA). An SPA typically downloads the initial application code (HTML, CSS and JavaScript) from the server-side, and the subsequent resources are dynamically loaded to the page, usually in response to user actions.

React, Angular.js, Ember.js and Vue.js are some of the most popular front-end web frameworks in use today. Each one offers specific advantages and limitations over the others, but Vue.js is popular for being an ideal middle ground.

This tutorial will help you learn Vue.js quickly. We’ll go over the key concepts of the framework as we build a new Vue app.

Knowledge of JavaScript is a prerequisite for using Vue.js.

Today, we will learn:

What is Vue.js?

Created by Evan You in 2013, Vue.js is a progressive, declarative JavaScript framework for building fast single-page applications. It is progressive because it can easily scale from a library to a full-featured framework.

Vue offers an adoptable ecosystem that can scale between a library and a full-featured framework. It has become increasingly popular over the years, with 176k GitHub stars

Based on the MVC architecture, Vue (pronounced “view”) is focused on the view layer only, and it provides a system that lets you declaratively make changes to the DOM. This means that you don’t have to worry about how your application’s UI is rendered or how changes are applied to the DOM.

Under the hood, Vue utilizes a Virtual DOM to make the required changes to your application UI and state.

There are a number of ways to add Vue to a project.

Import it as a CDN package on the page

On an existing HTML webpage, add the following line of code near the closing <body> tag.

<script src="https://unpkg.com/vue@next"></script>
Enter fullscreen mode Exit fullscreen mode

Using a package manager

You can install Vue on an existing project by running npm install vue@next.

Alternatively, run yarn add vue@next if you are using the Yarn package manager. The @next tag tells our package manager to install the latest stable version.

Using the official CLI tool

Vue provides a Command-Line Interface tool, which can scaffold a project with predefined build setups for a modern frontend workflow.

Towards the end of this article, we’ll explore the benefits using the CLI provides and learn how to set up a production-ready project using a starter template.

Note that using the CLI requires familiarity with front-end build tools.

Vue.js

Vue.js compared to other frameworks

There are three popular JavaScript front-end frameworks:

  • Vue.js
  • Angular
  • React

All these frameworks share a similar philosophy and purpose. One of the main differences is that Angular was developed by Google, and React is developed by Facebook. Vue.js does not have a large tech company behind its development.

Vue.js is often considered a middle ground. It offers more tools than React but fewer than Angular. On top of that, the syntax of Vue.js is simpler. Vue.js also offers built-in state management and vue-router, the official Vue.js router.

However, it does not feature HTTP client functionality or form validation. Vue focuses on building user interfaces and creating reusable components.

Vue.js also differs from other, smaller libraries.

  • jQuery is a small JavaScript library that makes vanilla JS easier to write. jQuery does have an additional build-step that Vue does not, which makes Vue more flexible.
  • Node.js is a cross-platform, back-end framework that executes JavaScript code on the server-side. Unlike Vue.js, no DOM is used.
  • Nuxt.js is a frontend framework based on Vue.js. Nuxt.js and Vue.js handle logic differently, since Vue always runs on the client side and Nuxt.js does not.

Concepts and features of Vue.js

Vue’s design allows you to adopt as little of the framework as you want, making it easy to integrate into an existing project. Below, we’ll build a simple To Do application to demonstrate Vue’s ease-of-adoption while learning about the framework’s core concepts.

Vue.js File Structure

Like many other frontend frameworks, Vue.js allows users to split a web page into reusable components, each with its own HTML, CSS, and JavaScript to render it.

Vue.js structure

HTML Template and Vue CDN

Let’s start by creating an index.html file in a folder named vue-todo. Open a terminal and run the following commands:

mkdir vue-todo
cd vue-todo
touch index.html
Enter fullscreen mode Exit fullscreen mode

We will start off with a blank HTML template and add Vue from a CDN. To do this, open the index.html file you just created with a text editor and add the following code:

<!DOCTYPE html>
<html>
 <head>
   <meta charset="utf-8" />
   <meta http-equiv="X-UA-Compatible" content="IE=edge" />
   <title>Vue!</title>
   <meta name="viewport" content="width=device-width, initial-scale=1" />
 </head>
 <body>
   <div id="app"></div>

   <script src="https://unpkg.com/vue@next"></script>
 </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Including the Vue package via the CDN as we’ve done above makes the Vue object available globally. This object contains methods for creating application instances and registering components.

Creating an App Instance

Vue applications are typically organized into a tree of nested, reusable components. The component used as a starting point for the application, referred to as the root component, is rendered when we mount it to the DOM.

Vue provides a method called createApp() which accepts options to configure the root component and returns an application instance. We can then mount the application using the mount() method.

Continuing with our example, add the following code to set up your Vue application:

<script src="https://unpkg.com/vue@next"></script>
<script type="text/javascript">
  const TodoApp = {};
  const app = Vue.createApp(TodoApp);
  app.mount("#app");
</script>
Enter fullscreen mode Exit fullscreen mode

We’re using the <div> in our document as the target DOM node for our app. Note that we can pass options to the createApp() method.

Let’s initialize our to-do list as an empty array for now. Modify the TodoApp object to look like this:

const TodoApp = {
  data() {
    return {
      todos: [],
    };
  },
};
Enter fullscreen mode Exit fullscreen mode

When a Vue instance is created, it looks for an element in the webpage to control. It can be defined by assigning that element an id (usually a div). This id is then mentioned in the Vue instance as the value of the el key.

<!-- This is the div that is assigned the id= 'app' -->
<div id='app'></div>

<script>
new Vue({
    // This `id` is used as a value of `el` so that it knows  
    // which element `Vue` should be mounted on.
    el: '#app'  
})
</script>
Enter fullscreen mode Exit fullscreen mode

Template Syntax

If you have some experience with HTML and JavaScript, what we have done so far should feel familiar. This is one of the advantages of Vue.js over front-end frameworks like React and Angular.

Going back to our application, we will need a way to render items in our To Do list and add/remove items. For rendering data, Vue provides a straightforward way to do this.

First, add an example To Do list item to your array:

todos: [
  {
    title: "Shop for Christmas",
  },
],
Enter fullscreen mode Exit fullscreen mode

Next, update your HTML to look like the following:

<ul>
  <li v-for="todo in todos">
    {{ todo.title }}
  </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

The v-for attribute here allows us to link and render a list to the DOM. It is called a directive, and as you can already guess, it behaves like a JavaScript for-in loop.

Directives are prefixed with v- to indicate that they are special attributes provided by Vue. They apply special reactive behavior to the rendered DOM.

The use of double curly braces interprets data from a component instance as plain text. This is known as text interpolation.

JavaScript expressions are supported and will be evaluated as JavaScript in the data scope of the current active instance.

Components and Props

Components are reusable Vue instances that can be attached to an application or root component instance. They accept the same options as a root instance, such as:

  • data
  • computed
  • watch
  • methods
  • lifecycle hooks

A component has to be registered to an application instance before it can be rendered. We can do this with the component() method. You’ll find components very useful for keeping your codebases neat and organized when you start building larger applications.

Let’s make a few changes to our Todo application to see components in action. First, we’ll replace the start and end <li> tags with the following:

<todo-item
  v-for="todo of todos"
  v-bind:title="todo.title"
></todo-item>
Enter fullscreen mode Exit fullscreen mode

Next, add the following just before app.mount():

app.component("todo-item", {
  props: {
    title: String,
  },
  template: `
    <li>
      {{ title }}
    </li>
  `,
});
Enter fullscreen mode Exit fullscreen mode

You can see that we’ve created and registered a new component named todo-item to our app instance. The props property specifies data that can be passed to the component from its parent application or component instance.

The value provided to the template property should be a string containing HTML to be rendered.

Components are rendered in HTML by passing the component name to a custom tag. In our example app, this looks like <todo-item></todo-item>. The v-bind directive is used to bind an attribute or a component prop to an expression.

Here, we use it to dynamically pass data from our loop to the <todo-item> component.

Methods

Component methods are accessible from within the component's template. We can add methods to a component instance by passing an object with the desired methods to the component’s methods option.

Vue automatically binds the this value for methods so that it always refers to the component instance.

Note: You should avoid using arrow methods when defining methods, as that prevents Vue from binding the appropriate this value.

Take a look at an example of using methods in a component instance below.

index.js:

const TodoApp = {
  data() {
    return {
      todos: [
        {
          title: "Shop for Christmas",
        },
      ],
      todo: "",
    };
  },
  methods: {
    addTodo() {
      if (this.$data.todo.length > 0) {
        this.$data.todos.push({ title: this.$data.todo });
        this.$data.todo = "";
      }
    },
  },
};
Enter fullscreen mode Exit fullscreen mode

index.html:

<div>
  <input v-model="todo" />
  <button v-on:click="addTodo">Add todo</button>
</div>
Enter fullscreen mode Exit fullscreen mode

Our component has been modified to have an extra data property, todo, the value of which we will bind to an <input /> tag in HTML. We also added an addTodo() method to create a new to-do item with the value of the input.

v-model is a directive used to create two-way data bindings on form input, textarea, and select elements. It automatically picks the correct way to update the element based on the input type. The v-on directive listens for DOM events.

In our example, it’s used to invoke the addTodo() method when the button is clicked.

Code examples of Vue.js

Now that we understand the basics of how to create a Vue.js app, let's dive more into the different functionalities with some code examples. These are common tasks that you'll likely implement in your own apps.

Listen for when an element is clicked

JS:

new Vue({
    el: '#app',

    methods: {
        doSomething() {
            alert('Clicked!');
        }
    }
});
Enter fullscreen mode Exit fullscreen mode

HTML:

<div id="app">
  <button @click="doSomething">Click here</button>
</div>
Enter fullscreen mode Exit fullscreen mode

Binding classes

JS:

new Vue({
    el: '#app',

    data: {
        className: 'red-text'
    }
});
Enter fullscreen mode Exit fullscreen mode

HTML:

<div id="app">
  <div id="content" :class="className">
    Text Text
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Update an element's content

JS:

new Vue({
    el: '#app',

    data: {
        content: ''
    }

});
Enter fullscreen mode Exit fullscreen mode

HTML:

<div id="app">
  <div v-html="content"></div>
  <input type="text" placeholder="Enter your text" v-model="content">
</div>
Enter fullscreen mode Exit fullscreen mode

Build a select input from an array

JS:

new Vue({

    el: '#app',

    data: {
        socialNetworks: ['Twitter', 'Facebook', 'TikTok', 'LinkedIn', 'MySpace']
    }

});
Enter fullscreen mode Exit fullscreen mode

HTML:

<div id="app">
  <span>Social Networks:</span>

  <select id="networks">
    <option v-for="(network, index) in socialNetworks" :value="index">{{ network }}</option>
  </select>
</div>
Enter fullscreen mode Exit fullscreen mode

Advanced uses of Vue.js

Our setup so far (including a packaged build from a CDN) looks fine and works very well for small to medium-sized projects, where JavaScript is only used to enhance certain views. In more complex projects however, or when your frontend is entirely driven by JavaScript, these disadvantages become apparent:

  • Global definitions force unique names for every component
  • String templates lack syntax highlighting and require ugly slashes for multiline HTML
  • No CSS support means that while HTML and JavaScript are modularized into components, CSS is conspicuously left out
  • No build step restricts us to HTML and ES5 JavaScript, rather than preprocessors like Pug (formerly Jade) and Babel

All of these are solved by single-file components with a .vue extension. There are also many components, libraries, and open-source tools available that can enhance your app’s functionality and development experience.

You can make use of Vue’s CLI to quickly bootstrap a project with the most common tooling configurations setup for you. To get started, run the following command.

It will install vue-cli globally and make the vue binary available from anywhere on your command line.

// using npm
npm install -g @vue/cli

// using yarn
yarn global add @vue/cli
Enter fullscreen mode Exit fullscreen mode

Once it’s installed, you can create a project by using the vue create app-name command. You will be provided with prompts about your project’s configuration. You can choose to go with a default or set up your own configuration.

Running this command with version 4.5 of the CLI gives the following output:

Vue.js output

If you choose to use the Vue v3 preset, the command will create a project directory that looks like the following:

Vue v3 preset

What to learn next

That’s all you need to get started using Vue with modern JavaScript tools and features to develop feature-rich applications!

While we’ve learned a lot building this really simple to-do application, we have barely scratched the surface of what Vue is capable of. There are also many more concepts still to learn, including the following:

  • Conditional rendering
  • Class and style bindings
  • Event and input modifiers
  • Vue.js plugins
  • Vuex: state management pattern

Educative’s course Hands-on Vue.js: Build a fully functional SPA will get you started on these concepts and more. You will also practically incorporate the concepts you learn by developing a fully working Vue.js Single Page Application that interacts with a backend server, APIs, and a database.

Throughout the course you will find quizzes and coding challenges to help strengthen your grasp of all the concepts.

Happy learning!

Continue reading about Vue.js on Educative

Start a discussion

What is your personal favorite JS framework to use? Was this article helpful? Let us know in the comments below!

Top comments (0)