javascriptroom guide

Vue.js Basics: A Complete Tutorial for Newbies

If you’re new to web development and looking to dive into JavaScript frameworks, Vue.js is an excellent starting point. Created by Evan You in 2014, Vue (pronounced "view") is a **progressive JavaScript framework** designed to build user interfaces. What makes Vue stand out is its gentle learning curve, flexibility, and focus on simplicity—perfect for beginners. Unlike some other frameworks, Vue doesn’t require you to learn a complex new syntax or paradigm upfront; it builds on standard HTML, CSS, and JavaScript, making it easy to adopt incrementally. Whether you want to add interactivity to a simple webpage or build a full-fledged single-page application (SPA), Vue has you covered. In this tutorial, we’ll walk through the fundamentals of Vue.js, from setup to core concepts, with hands-on examples to ensure you grasp each topic. By the end, you’ll be ready to build your first Vue app!

Table of Contents

  1. What is Vue.js?
  2. Setting Up Your First Vue.js Project
  3. The Vue Instance
  4. Vue Templates & Interpolation
  5. Directives: Vue’s HTML Superpowers
  6. Methods, Computed Properties & Watchers
  7. Components: Building Blocks of Vue Apps
  8. Lifecycle Hooks
  9. Putting It All Together: A Simple Todo App
  10. Conclusion
  11. References

What is Vue.js?

Vue.js (or “Vue”) is an open-source progressive JavaScript framework for building user interfaces (UIs) and single-page applications (SPAs). The term “progressive” means you can adopt Vue incrementally: use it for small features in an existing project (e.g., adding interactivity to a button) or scale it to build large, complex apps with its ecosystem (Vue Router for routing, Pinia for state management).

Why Vue.js?

  • Approachable: Uses HTML-based templates, so developers familiar with HTML/CSS/JS can start quickly.
  • Reactive: Automatically updates the DOM when data changes (no manual DOM manipulation!).
  • Flexible: Integrates with other libraries or existing projects.
  • Lightweight: ~33KB minified and gzipped (smaller than React or Angular).
  • Strong Community: Well-documented, with a large community for support.

Setting Up Your First Vue.js Project

Let’s get started with Vue! We’ll cover two setup methods: a quick CDN approach (best for learning) and Vue CLI (for production-ready projects).

Option 1: Using CDN (Quick Start)

The easiest way to try Vue is via a CDN (Content Delivery Network). Add this script tag to your HTML file:

<!DOCTYPE html>
<html>
<head>
    <title>Vue.js Basics</title>
    <!-- Include Vue via CDN -->
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
    <!-- Vue app will mount here -->
    <div id="app">
        {{ message }}
    </div>

    <script>
        // Create a Vue app instance
        const { createApp } = Vue;

        createApp({
            data() {
                return {
                    message: "Hello, Vue!"
                }
            }
        }).mount('#app'); // Mount to the element with id "app"
    </script>
</body>
</html>

Save this as index.html and open it in a browser. You’ll see “Hello, Vue!” displayed. That’s your first Vue app!

Option 2: Using Vue CLI (For Larger Projects)

For serious projects, use Vue CLI (Command Line Interface) to scaffold a project with tools like Babel, Webpack, and ESLint.

Prerequisites: Node.js (v14.0.0+ recommended) and npm (v6.0.0+). Download Node.js from nodejs.org.

Steps:

  1. Install Vue CLI globally:

    npm install -g @vue/cli
  2. Create a new project:

    vue create my-vue-app
  3. Follow the prompts to select a preset (choose “Default ([Vue 3] babel, eslint)” for simplicity).

  4. Navigate to the project folder and run the development server:

    cd my-vue-app
    npm run serve
  5. Open http://localhost:8080 in your browser—you’ll see a Vue welcome page!

The Vue Instance

Every Vue app starts with a Vue instance (or “app instance” in Vue 3). This instance connects your Vue code to a DOM element and manages data, methods, and reactivity.

In Vue 3, we use createApp() to initialize an app:

const { createApp } = Vue;

const app = createApp({
  // Options: data, methods, computed, etc.
  data() {
    return {
      message: "Hello from Vue Instance!"
    };
  }
});

app.mount("#app"); // Mount to <div id="app"></div>
  • data(): A function that returns an object containing reactive data properties (e.g., message).
  • mount("#app"): Attaches the Vue app to the DOM element with id="app".

Vue Templates & Interpolation

Vue uses HTML templates to define the UI. Templates are plain HTML with special Vue syntax for dynamic content.

Text Interpolation

Use double curly braces {{ }} to insert reactive data into the template:

<div id="app">
  <p>{{ message }}</p> <!-- Renders "Hello from Vue Instance!" -->
  <p>{{ 1 + 1 }}</p> <!-- Renders "2" (supports expressions) -->
  <p>{{ user.name.toUpperCase() }}</p> <!-- Renders "ALICE" -->
</div>

<script>
const app = Vue.createApp({
  data() {
    return {
      message: "Hello from Vue Instance!",
      user: { name: "alice" }
    };
  }
}).mount("#app");
</script>

Note: Only one expression is allowed in {{ }} (no statements like if or loops).

Directives: Vue’s HTML Superpowers

Directives are special attributes prefixed with v- that tell Vue to apply reactive behavior to the DOM. Let’s cover the most essential ones.

v-bind: Attribute Binding

Use v-bind (or shorthand :) to bind HTML attributes to reactive data.

Example: Bind an image’s src attribute:

<div id="app">
  <img v-bind:src="imageUrl" alt="Vue Logo">
  <!-- Shorthand: <img :src="imageUrl" alt="Vue Logo"> -->
</div>

<script>
const app = Vue.createApp({
  data() {
    return {
      imageUrl: "https://vuejs.org/images/logo.png"
    };
  }
}).mount("#app");
</script>

v-model: Two-Way Data Binding

v-model creates two-way binding between form inputs and data: changing the input updates the data, and changing the data updates the input.

Example with a text input:

<div id="app">
  <input v-model="username" placeholder="Enter your name">
  <p>Hello, {{ username }}!</p>
</div>

<script>
const app = Vue.createApp({
  data() {
    return {
      username: ""
    };
  }
}).mount("#app");
</script>

Try typing in the input—the username data property updates, and the paragraph updates automatically!

v-on: Event Handling

Use v-on (or shorthand @) to listen to DOM events (e.g., click, submit) and trigger methods.

Example: A button that increments a counter:

<div id="app">
  <p>Count: {{ count }}</p>
  <button v-on:click="increment">Increment</button>
  <!-- Shorthand: <button @click="increment">Increment</button> -->
</div>

<script>
const app = Vue.createApp({
  data() {
    return { count: 0 };
  },
  methods: {
    increment() {
      this.count++; // "this" refers to the app instance
    }
  }
}).mount("#app");
</script>

v-if, v-else, v-show: Conditionals

Conditionally render elements with v-if, v-else, v-else-if, or v-show.

  • v-if: Removes/inserts the element from the DOM (expensive for frequent toggling).
  • v-show: Toggles the display CSS property (cheaper for frequent toggling).

Example:

<div id="app">
  <p v-if="isLoggedIn">Welcome back!</p>
  <p v-else>Please log in.</p>

  <button @click="isLoggedIn = !isLoggedIn">Toggle Login</button>

  <p v-show="showMessage">This message is toggled with v-show</p>
</div>

<script>
const app = Vue.createApp({
  data() {
    return {
      isLoggedIn: false,
      showMessage: true
    };
  }
}).mount("#app");
</script>

v-for: Looping

Use v-for to render a list of items from an array or object.

Syntax: v-for="item in items" (or (item, index) in items for index).

Example with an array:

<div id="app">
  <ul>
    <li v-for="(todo, index) in todos" :key="index">
      {{ index + 1 }}. {{ todo }}
    </li>
  </ul>
</div>

<script>
const app = Vue.createApp({
  data() {
    return {
      todos: ["Learn Vue", "Build an app", "Deploy"]
    };
  }
}).mount("#app");
</script>
  • :key: Required for performance—helps Vue track item identity (use unique IDs in real apps, not indexes).

Methods, Computed Properties & Watchers

Vue provides three ways to work with data: methods, computed, and watchers.

Methods

methods are functions defined in the Vue instance to handle logic (e.g., event handlers).

methods: {
  greet() {
    return `Hello, ${this.username}!`;
  }
}

Call methods in templates with {{ greet() }} or @click="greet".

Computed Properties

computed properties are cached, reactive values derived from other data. Use them for complex calculations that depend on reactive data.

Why not just use methods? Methods run on every re-render, while computed properties only re-calculate when their dependencies change (caching!).

Example: Full name from first and last name:

<div id="app">
  <input v-model="firstName" placeholder="First name">
  <input v-model="lastName" placeholder="Last name">
  <p>Full Name: {{ fullName }}</p> <!-- Uses computed property -->
</div>

<script>
const app = Vue.createApp({
  data() {
    return { firstName: "", lastName: "" };
  },
  computed: {
    fullName() {
      return `${this.firstName} ${this.lastName}`.trim();
    }
  }
}).mount("#app");
</script>

Watchers

watchers react to changes in specific data properties. Use them for asynchronous or complex logic (e.g., API calls when data changes).

Example: Watch a search query and fetch data:

<div id="app">
  <input v-model="searchQuery" placeholder="Search...">
  <p v-if="loading">Loading...</p>
  <p v-else>{{ results }}</p>
</div>

<script>
const app = Vue.createApp({
  data() {
    return {
      searchQuery: "",
      results: "",
      loading: false
    };
  },
  watch: {
    searchQuery(newVal) {
      // Simulate API call
      this.loading = true;
      setTimeout(() => {
        this.results = `Results for "${newVal}"`;
        this.loading = false;
      }, 1000);
    }
  }
}).mount("#app");
</script>  

Components: Building Blocks of Vue Apps

Components are reusable, self-contained UI elements (e.g., buttons, cards, navigation bars). They make apps modular and easier to maintain.

Global vs. Local Components

  • Global Components: Registered once and usable anywhere in the app.
  • Local Components: Registered only in the parent component that needs them (better for scoping).

Global Component Example

const { createApp } = Vue;

// Register global component
app.component("welcome-message", {
  template: `
    <div>
      <h2>Welcome to Vue!</h2>
      <p>This is a global component.</p>
    </div>
  `
});

app.mount("#app");

Use it in the template:

<div id="app">
  <welcome-message></welcome-message>
</div>

Local Component Example

const app = createApp({
  components: {
    // Local component (only usable in this app)
    "user-card": {
      template: `
        <div class="card">
          <h3>{{ name }}</h3>
          <p>{{ role }}</p>
        </div>
      `,
      data() {
        return {
          name: "Alice",
          role: "Developer"
        };
      }
    }
  }
});

Component Props

Props are custom attributes to pass data from parent to child components.

Example: Pass a name prop to a user-card:

// Child component with prop
const userCard = {
  props: ["name"], // Declare prop
  template: `<div>Hello, {{ name }}!</div>`
};

// Parent component
const app = createApp({
  components: { userCard },
  data() {
    return { username: "Bob" };
  }
});

Use in template:

<div id="app">
  <user-card :name="username"></user-card> <!-- Pass prop with :name -->
</div>

Lifecycle Hooks

Vue instances go through a lifecycle (create, mount, update, unmount). Lifecycle hooks let you run code at specific stages.

Common hooks:

  • created(): Runs after the instance is initialized (data is reactive, but DOM not mounted).
  • mounted(): Runs after the instance is mounted to the DOM (access DOM here).
  • updated(): Runs after data changes and the DOM updates.
  • unmounted(): Runs after the instance is removed from the DOM.

Example using mounted():

const app = createApp({
  data() {
    return { message: "Hello" };
  },
  mounted() {
    console.log("App mounted! DOM is ready.");
    this.message = "Hello (updated after mount)";
  }
});

Putting It All Together: A Simple Todo App

Let’s build a todo app to apply what we’ve learned! Features: add todos, display todos, delete todos.

Step 1: HTML Template

<div id="app">
  <h1>Todo App</h1>
  
  <!-- Add Todo Form -->
  <form @submit.prevent="addTodo">
    <input 
      v-model="newTodo" 
      placeholder="Enter a new todo" 
      required
    >
    <button type="submit">Add</button>
  </form>

  <!-- Todo List -->
  <ul v-if="todos.length"> <!-- Show list only if todos exist -->
    <li v-for="(todo, index) in todos" :key="index">
      {{ todo }}
      <button @click="deleteTodo(index)">×</button>
    </li>
  </ul>
  <p v-else>No todos yet. Add one!</p> <!-- Show if no todos -->
</div>

Step 2: Vue Instance Logic

const { createApp } = Vue;

createApp({
  data() {
    return {
      todos: [], // Empty array to store todos
      newTodo: "" // Bound to input with v-model
    };
  },
  methods: {
    addTodo() {
      this.todos.push(this.newTodo); // Add new todo to array
      this.newTodo = ""; // Clear input
    },
    deleteTodo(index) {
      this.todos.splice(index, 1); // Remove todo at index
    }
  }
}).mount("#app");

How It Works:

  • v-model="newTodo" binds the input to newTodo.
  • @submit.prevent="addTodo" handles form submission (.prevent stops default form reload).
  • v-for loops through todos to display each item.
  • @click="deleteTodo(index)" removes the todo when the ”×” button is clicked.

Conclusion

You now know the basics of Vue.js! We covered setup, the Vue instance, templates, directives, data binding, methods, computed properties, watchers, components, lifecycle hooks, and built a todo app.

Vue’s gentle learning curve and powerful features make it a great choice for beginners and experts alike. Next steps: explore Vue Router (for multi-page apps), Pinia (state management), and the Composition API (Vue 3’s advanced syntax for reusing logic).

References

Happy coding! 🚀