Vue.js Tutorial: build a functional SPA from scratch
Tags: vue, javascript, tutorial
Published: 2023-02-20 18:20:53

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?](#what)
* [Vue.js compared to other frameworks](#compared)
* [Concepts and features of Vue.js](#concepts)
* [Code examples of Vue.js](#examples)
* [Advanced Vue.js uses](#advanced)
* [What to learn next](#next)

<a name="what"></a>

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

<br>


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

```js
<script src="https://unpkg.com/vue@next"></script>
```

<br>

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

<br>

### 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aaa5672jlsqqzzhdvjop.png)

<a name="compared"></a>

## 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](https://www.educative.io/blog/react-angular-vue-comparison?eid=5082902844932096) 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.

<br>

<a name="concepts"></a>

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

<br>

### 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pal0klfel9lqb7gtudm2.png)

<br>

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

```js
mkdir vue-todo
cd vue-todo
touch index.html
```

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:

```html
<!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>
```

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.

<br>

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

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

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: [],
    };
  },
};
```

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.

```html
<!-- 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>
```

<br>

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

```js
todos: [
  {
    title: "Shop for Christmas",
  },
],
```

Next, update your HTML to look like the following:

```html
<ul>
  <li v-for="todo in todos">
    {{ todo.title }}
  </li>
</ul>
```

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.

<br>

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

```html
<todo-item
  v-for="todo of todos"
  v-bind:title="todo.title"
></todo-item>
```

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

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

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.

<br>

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

```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 = "";
      }
    },
  },
};
```

**index.html:**

```html
<div>
  <input v-model="todo" />
  <button v-on:click="addTodo">Add todo</button>
</div>
```

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.

<br>

<a name="examples"></a>

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

<br>

### Listen for when an element is clicked

**JS:**

```js
new Vue({
    el: '#app',

    methods: {
        doSomething() {
            alert('Clicked!');
        }
    }
});
```

**HTML:**

```html
<div id="app">
  <button @click="doSomething">Click here</button>
</div>
```

<br>

### Binding classes

**JS:**

```js
new Vue({
    el: '#app',

    data: {
        className: 'red-text'
    }
});
```


**HTML:**

```html
<div id="app">
  <div id="content" :class="className">
    Text Text
  </div>
</div>
```

<br>

### Update an element's content

**JS:**

```js
new Vue({
    el: '#app',

    data: {
        content: ''
    }

});
```


**HTML:**

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

<br>

### Build a select input from an array

**JS:**

```js
new Vue({

    el: '#app',

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

});
```


**HTML:**

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

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

<br>

<a name="advanced"></a>

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


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

// using yarn
yarn global add @vue/cli
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dzdidrml8z2r3f9ovbdz.png)

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

![Vue v3 preset](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qmok14psgpf2ngdsay4p.png)

<br>

## 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](https://www.educative.io/courses/hands-on-vue-js-build-fully-functional-spa?eid=5082902844932096)** 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
* [Build an app from scratch with Vue.js](https://www.educative.io/blog/build-an-app-from-scratch-with-vue-js?eid=5082902844932096)
* [Write and test your first Vue.js component with Jest](https://www.educative.io/blog/vue-js-component-jest?eid=5082902844932096)
* [Comparing the most popular frontend JavaScript frameworks](https://www.educative.io/blog/compare-popular-frontend-javascript-frameworks?eid=5082902844932096)

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