Table of Contents
- Prerequisites
- Setting Up Vue.js
- Core Vue Concepts You’ll Need
- Building Your Interactive Page: A Todo List App
- Styling Your Interactive Page
- Testing & Debugging with Vue DevTools
- Conclusion
- References
Prerequisites
Before diving in, ensure you have:
- Basic knowledge of HTML, CSS, and JavaScript (ES6+ recommended).
- A code editor (e.g., VS Code).
- A modern web browser (Chrome, Firefox, Edge).
- Internet connection (to load Vue via CDN and optional styling libraries).
Setting Up Vue.js
Vue.js can be set up in multiple ways. For beginners, the CDN (Content Delivery Network) approach is the simplest—no complex build tools required.
Using the Vue CDN
Add the following script tag to the <head> of your HTML file to load Vue.js:
<!-- Load Vue.js from CDN -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
This loads the latest stable version of Vue 3 (the current major release). For production, specify a version (e.g., [email protected]) to avoid unexpected updates.
Core Vue Concepts You’ll Need
Let’s break down the foundational Vue concepts we’ll use to build our interactive page.
Data Binding
Vue’s reactivity system lets you bind data to the DOM seamlessly. The most common forms are:
Text Interpolation
Use double curly braces {{ }} to display data in the template:
<div id="app">
<h1>{{ message }}</h1>
</div>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
message: "Hello, Vue!"
}
}
}).mount('#app');
</script>
Here, message is a reactive data property. If you update message later (e.g., via a button click), the DOM will automatically update.
Attribute Binding
Use v-bind: (or the shorthand :) to bind data to HTML attributes:
<img :src="imageUrl" :alt="imageAlt">
In the Vue instance:
data() {
return {
imageUrl: "https://example.com/vue-logo.png",
imageAlt: "Vue.js Logo"
}
}
Two-Way Binding
Use v-model to sync form input values with reactive data (two-way binding):
<input v-model="username" placeholder="Enter your name">
<p>Hello, {{ username }}!</p>
Typing in the input updates username, and username updates the paragraph in real time.
Methods & Event Handling
Use v-on: (or shorthand @) to handle DOM events (e.g., clicks, input). Define methods in the Vue instance to respond to events.
Example: A counter that increments on button click
<div id="app">
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
<script>
createApp({
data() {
return {
count: 0
}
},
methods: {
increment() {
this.count++; // "this" refers to the Vue instance
}
}
}).mount('#app');
</script>
Conditional Rendering
Use v-if/v-else/v-else-if to conditionally render elements (adds/removes from the DOM) or v-show (toggles display: none):
<div v-if="isLoggedIn">Welcome back!</div>
<div v-else>Please log in.</div>
<!-- Toggle visibility with v-show -->
<p v-show="hasNotifications">You have unread messages.</p>
List Rendering
Use v-for to loop through arrays and render lists. Always include a :key attribute for performance:
<ul>
<li v-for="(item, index) in items" :key="index">
{{ index + 1 }}. {{ item }}
</li>
</ul>
In the Vue instance:
data() {
return {
items: ["Learn Vue", "Build an app", "Deploy!"]
}
}
Building Your Interactive Page: A Todo List App
Now, let’s combine these concepts to build a todo list with the following features:
- Add new todos via an input field.
- Mark todos as “completed.”
- Delete todos.
- Show a message if no todos exist.
Step 1: Project Setup
Create a new HTML file (e.g., index.html) and set up the basic structure. Include the Vue CDN and a CSS library (we’ll use Bootstrap for simplicity):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue Todo List</title>
<!-- Bootstrap for styling (optional but helpful) -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Vue.js CDN -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div class="container mt-5" id="app">
<!-- Todo app content will go here -->
</div>
<script>
// Vue app logic will go here
</script>
</body>
</html>
Step 2: Define the Vue Instance
Initialize the Vue app and define reactive data for todos and a new todo input:
const { createApp } = Vue;
createApp({
data() {
return {
newTodo: "", // Binds to the input field via v-model
todos: [
// Sample initial todos
{ id: 1, text: "Learn Vue basics", completed: false },
{ id: 2, text: "Build a todo app", completed: true }
]
};
}
}).mount("#app");
Step 3: Add Todo Functionality
Add an input field to enter new todos and a button to add them to the list. Use v-model for two-way binding and @click to trigger an addTodo method:
Template (inside #app):
<div class="card p-4">
<h2 class="text-center mb-4">Todo List</h2>
<!-- Add Todo Input -->
<div class="input-group mb-3">
<input
v-model="newTodo"
@keyup.enter="addTodo" <!-- Add on Enter key press -->
type="text"
class="form-control"
placeholder="Add a new todo..."
>
<button @click="addTodo" class="btn btn-primary">Add</button>
</div>
<!-- Todo List -->
<ul class="list-group">
<!-- Todo items will go here -->
</ul>
</div>
Add the addTodo method to the Vue instance:
methods: {
addTodo() {
if (this.newTodo.trim()) { // Ignore empty/whitespace todos
this.todos.push({
id: Date.now(), // Unique ID using timestamp
text: this.newTodo.trim(),
completed: false
});
this.newTodo = ""; // Clear input after adding
}
}
}
Step 4: Mark Todos as Complete
Use v-for to render todos and v-bind:class to style completed todos (e.g., strikethrough text). Add a checkbox to toggle completed status:
Update the <ul> in the template:
<ul class="list-group">
<li
v-for="todo in todos"
:key="todo.id"
class="list-group-item d-flex align-items-center justify-content-between"
>
<div class="d-flex align-items-center">
<input
type="checkbox"
v-model="todo.completed"
class="me-3"
>
<span :class="{ 'text-decoration-line-through text-muted': todo.completed }">
{{ todo.text }}
</span>
</div>
<!-- Delete button will go here -->
</li>
<!-- Show message if no todos -->
<li v-if="todos.length === 0" class="list-group-item text-center text-muted">
No todos yet. Add your first todo!
</li>
</ul>
Here, :class="{ 'text-decoration-line-through text-muted': todo.completed }" applies styles conditionally when todo.completed is true.
Step 5: Delete Todos
Add a delete button for each todo and a deleteTodo method to remove todos from the list:
Add the delete button to each list item:
<button @click="deleteTodo(todo.id)" class="btn btn-danger btn-sm">×</button>
Add the deleteTodo method to the Vue instance:
methods: {
// ... (addTodo method)
deleteTodo(todoId) {
this.todos = this.todos.filter(todo => todo.id !== todoId);
}
}
Styling Your Interactive Page
With Bootstrap, the app already looks clean, but you can customize styles further. For example, highlight completed todos with a light gray background:
/* Add to <style> in <head> */
.list-group-item {
transition: all 0.2s;
}
.list-group-item:hover {
background-color: #f8f9fa;
}
/* Completed todo style */
.list-group-item .text-decoration-line-through {
opacity: 0.7;
}
Testing & Debugging with Vue DevTools
Vue DevTools is a browser extension that lets you inspect Vue components, track reactive data, and debug your app in real time.
Install Vue DevTools:
- Chrome/Firefox: Search for “Vue DevTools” in the Chrome Web Store or Firefox Add-ons.
- Edge: Use the Chrome extension via the Microsoft Edge Add-ons store.
Once installed, open your app in the browser and launch DevTools (F12 or Ctrl+Shift+I). You’ll see a “Vue” tab to inspect your app’s data, methods, and components.
Conclusion
You’ve built a fully interactive todo list with Vue.js! You learned:
- How to set up Vue.js via CDN.
- Core concepts: data binding (
{{ }},v-bind,v-model), event handling (v-on), conditional rendering (v-if), and list rendering (v-for). - How to combine these to build a functional app.
- Styling with conditional classes and debugging with Vue DevTools.
Vue’s simplicity and reactivity make it a joy to build interactive UIs. Next steps: explore Vue 3’s Composition API, Vue Router for multi-page apps, or Pinia for state management!