Table of Contents
- Getting Started with Vue.js
- The Vue Instance
- Vue Templates: HTML with Superpowers
- Reactivity: The Heart of Vue
- Components: Building Blocks of Vue Apps
- Props and Events: Communication Between Components
- Lifecycle Hooks: Understanding Vue’s Lifecycle
- Vue Router: Adding Navigation
- State Management with Pinia
- Deploying Your Vue App
- Conclusion
- References
1. Getting Started with Vue.js
Before diving into code, let’s set up your Vue development environment. Vue offers multiple installation methods to suit different needs:
Option 1: CDN (Quick Prototyping)
For small projects or learning, you can include Vue directly via a CDN. Add this script to your HTML file:
<!-- Vue 3 (latest version) -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
Now you can start using Vue in a single HTML file. Try this minimal example:
<!DOCTYPE html>
<html>
<head>
<title>Vue CDN Example</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
{{ message }}
</div>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
message: "Hello, Vue!"
}
}
}).mount('#app');
</script>
</body>
</html>
Open this file in a browser, and you’ll see “Hello, Vue!”—your first Vue app!
Option 2: Vue CLI (Legacy, but Still Used)
Vue CLI is a command-line tool for scaffolding Vue projects. While it’s been superseded by Vite, it’s still widely used.
Setup:
- Install Node.js (v14.0+ recommended) from nodejs.org.
- Install Vue CLI globally:
npm install -g @vue/cli - Create a project:
vue create my-vue-app - Follow the prompts to select features (e.g., Babel, TypeScript, Vue Router).
Option 3: Vite (Recommended for New Projects)
Vite is a next-gen build tool that’s faster and more efficient than Vue CLI. It’s the official recommendation for Vue 3.
Setup:
- Ensure Node.js (v14.18+ or v16+) is installed.
- Create a new Vue project with Vite:
npm create vue@latest - Answer the prompts (name your project, enable TypeScript, Vue Router, Pinia, etc.).
- Navigate to the project folder and install dependencies:
cd my-vue-app npm install - Run the development server:
npm run dev
Your app will be live at http://localhost:5173!
2. The Vue Instance
Every Vue app starts with a Vue instance (or “app instance” in Vue 3). This instance connects your data and logic to the DOM.
Creating an App Instance
In Vue 3, you use createApp() to initialize an app:
import { createApp } from 'vue';
import App from './App.vue'; // Root component
const app = createApp(App);
app.mount('#app'); // Mounts the app to the DOM element with id="app"
The mount('#app') method attaches the app to the HTML element <div id="app"></div>.
App Options: Data, Methods, and More
The app instance accepts options to define behavior. The most common are:
data(): Returns an object of reactive data properties.methods: Object of functions to handle logic.
Example:
<!-- In your HTML -->
<div id="app">
<p>{{ count }}</p>
<button @click="increment">Increment</button>
</div>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
count: 0 // Reactive data property
};
},
methods: {
increment() {
this.count++; // "this" refers to the app instance
}
}
}).mount('#app');
</script>
Here, count is reactive: when it changes, the DOM updates automatically. The increment method modifies count, and @click (shorthand for v-on:click) triggers the method.
3. Vue Templates: HTML with Superpowers
Vue templates extend HTML with special syntax to bind data and logic. Let’s explore key features:
Text Interpolation
Use double curly braces {{ }} to insert data into the DOM:
<div>{{ message }}</div>
data() {
return {
message: "Hello, Vue!" // Renders as "Hello, Vue!"
};
}
Directives: Special HTML Attributes
Directives are prefixed with v- and apply reactive behavior to the DOM.
v-bind: Dynamic Attributes
Bind HTML attributes to data with v-bind: (shorthand :):
<img v-bind:src="imageUrl" alt="Vue Logo">
<!-- Shorthand -->
<img :src="imageUrl" alt="Vue Logo">
data() {
return {
imageUrl: "https://vuejs.org/images/logo.png"
};
}
v-on: Event Handling
Listen to DOM events with v-on: (shorthand @):
<button v-on:click="greet">Say Hello</button>
<!-- Shorthand -->
<button @click="greet">Say Hello</button>
methods: {
greet() {
alert("Hello!");
}
}
v-model: Two-Way Binding
v-model creates two-way binding between form inputs and data:
<input v-model="name" placeholder="Enter your name">
<p>Hello, {{ name }}!</p>
data() {
return {
name: "" // Updates as the user types
};
}
v-for: List Rendering
Loop through arrays with v-for:
<ul>
<li v-for="(item, index) in items" :key="index">
{{ index + 1 }}. {{ item }}
</li>
</ul>
data() {
return {
items: ["Apple", "Banana", "Cherry"]
};
}
Always use :key with v-for to help Vue track list items efficiently.
v-if / v-else: Conditional Rendering
Conditionally render elements with v-if, v-else-if, and v-else:
<p v-if="score >= 90">A+</p>
<p v-else-if="score >= 80">A</p>
<p v-else>Pass</p>
data() {
return {
score: 85 // Renders "A"
};
}
4. Reactivity: The Heart of Vue
Vue’s reactivity system automatically updates the DOM when data changes. Here’s how it works:
How Reactivity Works
In Vue 3, reactivity is powered by ES6 Proxies. When you define data properties, Vue wraps them in a proxy that tracks dependencies (e.g., template expressions, computed properties) and triggers updates when the data changes.
Key Rule: Declare Data Upfront
For reactivity to work, data properties must be declared in the data() function. Adding new properties later won’t trigger updates.
Bad:
data() {
return {}; // Empty data
}
// Later...
this.newProperty = "Hello"; // Not reactive!
Good:
data() {
return {
newProperty: null // Declare upfront
};
}
// Later...
this.newProperty = "Hello"; // Reactive!
Example: Reactive Counter
<div id="app">
<p>Count: {{ count }}</p>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</div>
<script>
const { createApp } = Vue;
createApp({
data() {
return { count: 0 };
},
methods: {
increment() { this.count++; },
decrement() { this.count--; }
}
}).mount('#app');
</script>
Clicking the buttons updates count, and Vue automatically re-renders the {{ count }} interpolation.
5. Components: Building Blocks of Vue Apps
Components are reusable, self-contained units that encapsulate HTML, CSS, and JavaScript. They let you split your app into manageable parts.
Component Structure
A Vue component typically has three sections:
<template>: HTML markup.<script>: Logic (data, methods, etc.).<style>: CSS (scoped to the component by addingscoped).
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.
Example: Global Component
Register a global component in your main app file:
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import Greeting from './components/Greeting.vue'; // Import component
const app = createApp(App);
app.component('Greeting', Greeting); // Register globally
app.mount('#app');
Now use it in any template:
<!-- In any component -->
<Greeting />
Example: Local Component
Register a component only in the parent:
<!-- ParentComponent.vue -->
<template>
<div>
<LocalGreeting /> <!-- Use local component -->
</div>
</template>
<script>
import LocalGreeting from './LocalGreeting.vue'; // Import
export default {
components: {
LocalGreeting // Register locally
}
};
</script>
Single-File Components (SFCs)
SFCs (.vue files) are the standard way to write Vue components. Here’s a simple Greeting.vue:
<!-- Greeting.vue -->
<template>
<h1>Hello, {{ name }}!</h1>
</template>
<script>
export default {
data() {
return {
name: "Vue Developer"
};
}
};
</script>
<style scoped>
h1 {
color: blue;
}
</style>
The scoped attribute in <style> ensures CSS only applies to this component.
6. Props and Events: Communication Between Components
Components need to communicate. Props send data from parent to child, and events send data from child to parent.
Props: Parent → Child
Props are custom attributes for passing data to child components.
Step 1: Define Props in Child Component
<!-- ChildComponent.vue -->
<template>
<p>Parent says: {{ message }}</p>
</template>
<script>
export default {
props: {
message: {
type: String, // Validate prop type
required: true // Make it required
}
}
};
</script>
Step 2: Pass Props from Parent
<!-- ParentComponent.vue -->
<template>
<ChildComponent message="Hello from Parent!" />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: { ChildComponent }
};
</script>
Events: Child → Parent
Children emit events to send data to parents using this.$emit(eventName, data).
Step 1: Emit Event in Child
<!-- ChildComponent.vue -->
<template>
<button @click="sendMessage">Send to Parent</button>
</template>
<script>
export default {
methods: {
sendMessage() {
this.$emit('child-message', 'Hello from Child!'); // Emit event
}
}
};
</script>
Step 2: Listen to Event in Parent
<!-- ParentComponent.vue -->
<template>
<ChildComponent @child-message="handleMessage" />
<p>Child said: {{ childMessage }}</p>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: { ChildComponent },
data() {
return { childMessage: "" };
},
methods: {
handleMessage(message) {
this.childMessage = message; // Update parent data
}
}
};
</script>
7. Lifecycle Hooks: Understanding Vue’s Lifecycle
Vue components go through a series of stages from creation to destruction. Lifecycle hooks let you run code at specific stages.
Common Lifecycle Hooks
| Hook | When It Runs | Use Case Example |
|---|---|---|
beforeCreate | Before the component is initialized. | Rarely used. |
created | After data and methods are initialized. | Fetch initial data from an API. |
beforeMount | Before the component is mounted to the DOM. | Prepare data for rendering. |
mounted | After the component is mounted to the DOM. | Access DOM elements, start timers. |
beforeUpdate | Before data changes cause a re-render. | Clean up before updates. |
updated | After data changes and re-render. | Perform post-update DOM operations. |
beforeUnmount | Before the component is removed from the DOM. | Clean up timers, event listeners. |
unmounted | After the component is removed. | Final cleanup. |
Example: Using mounted to Fetch Data
<template>
<ul>
<li v-for="post in posts" :key="post.id">{{ post.title }}</li>
</ul>
</template>
<script>
export default {
data() {
return { posts: [] };
},
mounted() {
// Fetch data when component is mounted
fetch('https://jsonplaceholder.typicode.com/posts')
.then(res => res.json())
.then(data => this.posts = data.slice(0, 5)); // Show first 5 posts
}
};
</script>
8. Vue Router: Adding Navigation
Vue Router is the official routing library for Vue apps, enabling single-page application (SPA) navigation.
Setup with Vite
If you used npm create vue@latest, select “Vue Router” during setup. Otherwise:
npm install vue-router@4
Basic Routing Example
Step 1: Define Routes
Create src/router/index.js:
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';
const routes = [
{ path: '/', name: 'Home', component: Home },
{ path: '/about', name: 'About', component: About }
];
const router = createRouter({
history: createWebHistory(), // Uses HTML5 history mode
routes
});
export default router;
Step 2: Register Router in App
In main.js:
import { createApp } from 'vue';
import App from './App.vue';
import router from './router'; // Import router
createApp(App)
.use(router) // Use the router
.mount('#app');
Step 3: Add Navigation Links and View
In App.vue:
<template>
<nav>
<!-- Router links (replace <a> tags) -->
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</nav>
<!-- Where routed components render -->
<router-view />
</template>
<style>
/* Style active router link */
.router-link-active {
color: blue;
font-weight: bold;
}
</style>
Dynamic Routes
Use :param in the path to match dynamic values (e.g., user IDs):
// router/index.js
{ path: '/user/:id', name: 'User', component: User }
Access the parameter in the component:
<!-- User.vue -->
<template>
<p>User ID: {{ $route.params.id }}</p>
</template>
9. State Management with Pinia
Pinia is Vue’s official state management library (replaces Vuex). Use it to share data across components.
Setup with Vite
Select “Pinia” during npm create vue@latest setup, or install manually:
npm install pinia
Example: Counter Store
Step 1: Create a Store
Create src/stores/counter.js:
import { defineStore } from 'pinia';
// Define a store with id "counter"
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }), // Reactive state
getters: {
doubleCount: (state) => state.count * 2 // Computed-like values
},
actions: {
increment() { state.count++; }, // Methods to modify state
decrement() { state.count--; }
}
});
Step 2: Use the Store in Components
<!-- AnyComponent.vue -->
<template>
<p>Count: {{ counterStore.count }}</p>
<p>Double: {{ counterStore.doubleCount }}</p>
<button @click="counterStore.increment">+</button>
<button @click="counterStore.decrement">-</button>
</template>
<script>
import { useCounterStore } from '../stores/counter';
export default {
setup() {
const counterStore = useCounterStore();
return { counterStore };
}
};
</script>
10. Deploying Your Vue App
Once your app is ready, build it for production and deploy it to a hosting service.
Build for Production
Run the build command to generate optimized static files:
npm run build
This creates a dist/ folder with HTML, CSS, and JS files.
Deploy Options
- Netlify: Connect your GitHub repo, set build command
npm run build, and publish directorydist. - Vercel: Similar to Netlify; import your repo and deploy.
- GitHub Pages: Push the
dist/folder to agh-pagesbranch (usegh-pagespackage for automation).
Example: Deploy to Netlify
- Push your code to GitHub.
- Go to Netlify and import your repo.
- Set build settings:
- Build command:
npm run build - Publish directory:
dist
- Build command:
- Click “Deploy”—your app will be live!
11. Conclusion
You’ve now learned the fundamentals of Vue.js: from setting up your project and creating components to routing, state management, and deployment. Vue’s simplicity and flexibility make it a great choice for building everything from small interactive widgets to large-scale SPAs.
To continue your journey:
- Explore the Vue 3 Documentation.
- Learn the Composition API (a more flexible alternative to the Options API used here).
- Dive into testing with Vue Test Utils.
- Join the Vue community on Discord or Reddit.
12. References
- Vue.js Official Documentation
- Vue Router Documentation
- Pinia Documentation
- Vite Documentation
- Vue School (Free Tutorials)
- MDN Web Docs (JavaScript/HTML/CSS)
Happy coding! 🚀