Vue.js First App
Introduction
Welcome to the exciting world of Vue.js! In this tutorial, you'll create your very first Vue application. Vue.js is a progressive JavaScript framework used to build user interfaces and single-page applications. It's designed to be incrementally adoptable, meaning you can start small and gradually incorporate more Vue features as your needs grow.
By the end of this guide, you'll have built a simple but functional Vue application and understand the core concepts that make Vue so powerful and developer-friendly.
Prerequisites
Before we start, make sure you have:
- Basic knowledge of HTML, CSS, and JavaScript
- A text editor (VS Code, Sublime Text, etc.)
- Node.js and npm installed (optional for this basic tutorial)
Getting Started with Vue.js
Method 1: Using Vue via CDN (Simplest Approach)
For your first Vue app, we'll use the CDN approach as it requires minimal setup.
Create a new file called index.html
and add the following code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My First Vue App</title>
<!-- Import Vue.js from CDN -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<style>
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.completed {
text-decoration: line-through;
color: #888;
}
.task-list {
margin-top: 20px;
}
.task-item {
padding: 10px;
margin: 5px 0;
background-color: #f5f5f5;
border-radius: 4px;
display: flex;
justify-content: space-between;
}
</style>
</head>
<body>
<!-- This is where our Vue app will be mounted -->
<div id="app">
<h1>{{ title }}</h1>
<div>
<input
type="text"
v-model="newTask"
@keyup.enter="addTask"
placeholder="Enter a new task"
/>
<button @click="addTask">Add Task</button>
</div>
<div class="task-list">
<div v-if="tasks.length === 0">No tasks yet! Add one above.</div>
<div
v-for="(task, index) in tasks"
:key="index"
class="task-item"
>
<span :class="{ completed: task.completed }">
{{ task.text }}
</span>
<div>
<button @click="toggleComplete(index)">
{{ task.completed ? 'Undo' : 'Complete' }}
</button>
<button @click="removeTask(index)">Delete</button>
</div>
</div>
</div>
<div v-if="tasks.length > 0">
<p>{{ completedCount }} out of {{ tasks.length }} tasks completed</p>
</div>
</div>
<script>
// Create a Vue application
const { createApp, ref, computed } = Vue;
createApp({
setup() {
// Reactive state
const title = ref('My Task List');
const newTask = ref('');
const tasks = ref([]);
// Computed property
const completedCount = computed(() => {
return tasks.value.filter(task => task.completed).length;
});
// Methods
function addTask() {
if (newTask.value.trim()) {
tasks.value.push({
text: newTask.value,
completed: false
});
newTask.value = '';
}
}
function removeTask(index) {
tasks.value.splice(index, 1);
}
function toggleComplete(index) {
tasks.value[index].completed = !tasks.value[index].completed;
}
// Expose managed state as return value
return {
title,
newTask,
tasks,
completedCount,
addTask,
removeTask,
toggleComplete
};
}
}).mount('#app');
</script>
</body>
</html>
Method 2: Using Vue CLI (Advanced Setup)
For a more robust setup, you can use Vue CLI. This method is recommended for larger projects:
# Install Vue CLI (do this only once)
npm install -g @vue/cli
# Create a new project
vue create my-first-app
# Navigate into the project folder
cd my-first-app
# Start the development server
npm run serve
Understanding the Code
Let's break down the key concepts from our task list application:
1. Vue Instance Creation
const { createApp, ref, computed } = Vue;
createApp({
setup() {
// Your code here
}
}).mount('#app');
This creates a Vue application and mounts it to the DOM element with ID 'app'. The setup()
function is the entry point in Vue 3's Composition API.
2. Reactive Data with ref
const title = ref('My Task List');
const newTask = ref('');
const tasks = ref([]);
Vue's reactivity system allows us to declare reactive data using ref()
. When this data changes, any components using it will automatically update.
3. Text Interpolation with Double Curly Braces
<h1>{{ title }}</h1>
This is how Vue binds data to the text content of an element. It will automatically update when title
changes.
4. Directives
Vue uses special attributes called directives that apply reactive behavior to the DOM:
v-model: Two-way Data Binding
<input type="text" v-model="newTask" />
This creates a two-way binding between the input field and the newTask
variable.
v-for: List Rendering
<div v-for="(task, index) in tasks" :key="index" class="task-item">
<!-- content -->
</div>
This directive renders a list of items based on an array.
v-if and v-else: Conditional Rendering
<div v-if="tasks.length === 0">No tasks yet! Add one above.</div>
Shows or hides elements based on a condition.
v-bind or : (shorthand): Attribute Binding
<span :class="{ completed: task.completed }">
This binds an HTML attribute to a reactive property. The :class
syntax allows conditional class application.
v-on or @ (shorthand): Event Handling
<button @click="addTask">Add Task</button>
This attaches an event listener to the button.
5. Computed Properties
const completedCount = computed(() => {
return tasks.value.filter(task => task.completed).length;
});
Computed properties are cached and only re-evaluate when their dependencies change. They're perfect for derived values.
Extending Your App
Adding Local Storage Persistence
Let's enhance our app to save tasks in the browser's localStorage:
// Inside setup() function
// Load tasks from localStorage when app starts
const tasks = ref(JSON.parse(localStorage.getItem('tasks') || '[]'));
// Watch for changes to tasks and save to localStorage
watch(tasks, (newTasks) => {
localStorage.setItem('tasks', JSON.stringify(newTasks));
}, { deep: true });
Don't forget to import watch
at the top:
const { createApp, ref, computed, watch } = Vue;
Adding Task Filtering
Let's add the ability to filter tasks:
<!-- Add these buttons below the task list -->
<div class="filters">
<button @click="filter = 'all'">All</button>
<button @click="filter = 'active'">Active</button>
<button @click="filter = 'completed'">Completed</button>
</div>
<!-- Update the v-for to use filteredTasks -->
<div
v-for="(task, index) in filteredTasks"
:key="index"
class="task-item"
>
<!-- Rest remains the same -->
</div>
Add the filter logic in your JavaScript:
// Inside setup() function
const filter = ref('all');
const filteredTasks = computed(() => {
switch (filter.value) {
case 'active':
return tasks.value.filter(task => !task.completed);
case 'completed':
return tasks.value.filter(task => task.completed);
default:
return tasks.value;
}
});
// Don't forget to return filter and filteredTasks in your setup() function
return {
// other returns...
filter,
filteredTasks
};
The Vue Lifecycle
Understanding the Vue lifecycle is crucial for more advanced applications:
In Vue 3's Composition API, we can hook into these lifecycle events:
import { onMounted, onBeforeUnmount } from 'vue';
// Inside setup() function
onMounted(() => {
console.log('Component is mounted!');
});
onBeforeUnmount(() => {
console.log('Component is about to be unmounted!');
});
Best Practices
- Keep components small and focused - Each component should do one thing well
- Use props for component communication - Pass data from parent to child components
- Use emits for child-to-parent communication - Emit events when children need to notify parents
- Use computed properties for derived values - Don't calculate values in templates
- Avoid complex logic in templates - Move complex logic to methods or computed properties
Summary
Congratulations! You've built your first Vue.js application—a functional task list with the ability to add, complete, and remove tasks. We've covered:
- Setting up a Vue.js application using CDN
- Creating reactive data with
ref()
- Using Vue directives (
v-model
,v-for
,v-if
,v-bind
,v-on
) - Computed properties
- Event handling
- Conditional rendering
- List rendering
- Basic Vue application structure
This is just the beginning of your Vue.js journey. As you get more comfortable, you'll want to explore Vue components, the Vue router, state management with Pinia or Vuex, and much more.
Exercises
- Add the ability to edit existing tasks
- Implement task categories or priority levels
- Add due dates to your tasks
- Create a dark/light theme toggle
- Make the app responsive for mobile devices
Additional Resources
Happy coding with Vue.js!
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)