Table of Contents
- What is Vue.js?
- Setting Up Your Development Environment
- Vue.js Core Concepts
- 3.1 Reactivity: The Heart of Vue
- 3.2 The Vue Instance
- 3.3 Templates: Declarative Rendering
- 3.4 Directives: Powering Template Logic
- 3.5 Components: Building Blocks of Vue Apps
- 3.6 Props: Passing Data to Child Components
- 3.7 Events: Child-to-Parent Communication
- 3.8 Lifecycle Hooks: Managing Component State Over Time
- State Management with Pinia
- Routing with Vue Router
- Building a Mini Project: Todo App
- Advanced Tips for Vue.js Development
- References
1. What is Vue.js?
Vue.js (pronounced /vjuː/, like “view”) is an open-source progressive JavaScript framework for building user interfaces. Created by Evan You in 2014, Vue is designed to be incrementally adoptable—you can use it for small features in an existing app or scale it up to a full SPA.
Key Features of Vue.js:
- Reactivity: Vue automatically updates the DOM when your data changes (no manual DOM manipulation!).
- Component-Based Architecture: Break your app into reusable, self-contained components.
- Template Syntax: HTML-based templates with Vue-specific directives for dynamic rendering.
- Flexibility: Integrate with other libraries/tools (e.g., React, Angular) or use it standalone.
- Gentle Learning Curve: Easier to pick up than React or Angular, especially for developers familiar with HTML/CSS/JS.
Vue vs. React vs. Angular:
- React: Uses JSX (JavaScript in HTML) and a virtual DOM; more flexible but steeper learning curve.
- Angular: A full-featured framework (opinionated, includes routing/state management); heavier and more complex.
- Vue: Balances simplicity and power, with HTML templates and reactivity out of the box—ideal for beginners and rapid development.
2. Setting Up Your Development Environment
To start building Vue apps, you’ll need:
Prerequisites:
- Node.js (v14.0+ recommended) and npm (Node Package Manager). Download from nodejs.org.
Step 1: Install Vue CLI
Vue CLI (Command Line Interface) is the official tool for scaffolding Vue projects. Install it globally via npm:
npm install -g @vue/cli
Verify installation:
vue --version
# Should output something like @vue/cli 5.0.8
Step 2: Create a New Vue Project
Run vue create to generate a project. Let’s name it vue-essentials-demo:
vue create vue-essentials-demo
You’ll be prompted to select a preset. Choose Default (Vue 3) for the latest features (Vue 3 uses the Composition API, which we’ll cover later).
Step 3: Navigate to the Project and Run the Dev Server
cd vue-essentials-demo
npm run serve
Your app will start at http://localhost:8080. Open it in your browser—you’ll see the default Vue welcome page!
Project Structure Explained:
Here’s a simplified breakdown of the generated files:
vue-essentials-demo/
├── node_modules/ # Dependencies
├── public/ # Static files (index.html, favicon)
├── src/ # Source code
│ ├── assets/ # Images, CSS, etc.
│ ├── components/ # Reusable components
│ ├── App.vue # Root component
│ └── main.js # Entry point (mounts Vue to the DOM)
├── package.json # Project metadata and scripts
└── README.md # Project documentation
3. Vue.js Core Concepts
Let’s explore the building blocks of Vue.js, starting with reactivity—the magic that makes Vue tick.
3.1 Reactivity: The Heart of Vue
Vue’s reactivity system automatically tracks changes to your data and updates the DOM. Here’s a simple example:
In src/App.vue, replace the template with:
<template>
<div>
<p>{{ message }}</p>
<button @click="updateMessage">Change Message</button>
</div>
</template>
<script>
export default {
data() {
return {
message: "Hello, Vue!"
};
},
methods: {
updateMessage() {
this.message = "Vue is reactive!"; // DOM updates automatically!
}
}
};
</script>
How it works:
- The
data()function returns an object with reactive properties (e.g.,message). - When
updateMessageruns,this.messagechanges, and Vue detects this, updating the<p>tag.
3.2 The Vue Instance
Every Vue app starts with a Vue instance (or “component instance” in Vue 3). It’s the root of your app, connecting data, methods, and the DOM.
In main.js, the entry point, we create and mount the root instance:
import { createApp } from 'vue';
import App from './App.vue';
createApp(App).mount('#app'); // Mounts App.vue to the DOM element with id="app"
3.3 Templates: Declarative Rendering
Vue uses HTML-based templates to render data. Use mustache syntax {{ }} for text interpolation:
<template>
<p>{{ name.toUpperCase() }}</p> <!-- Output: "ALICE" -->
<p>{{ age > 18 ? "Adult" : "Minor" }}</p> <!-- Conditional rendering -->
</template>
<script>
export default {
data() {
return {
name: "Alice",
age: 25
};
}
};
</script>
Templates support JavaScript expressions, but avoid complex logic (keep that in methods or computed properties).
3.4 Directives: Powering Template Logic
Directives are special attributes prefixed with v- that add dynamic behavior to the DOM.
Common Directives:
-
v-bind: Bind an attribute to a data property (shorthand::).<img v-bind:src="imageUrl" alt="Vue Logo"> <!-- Shorthand: <img :src="imageUrl"> --> -
v-model: Two-way data binding for form inputs (syncs input value with data).<input v-model="username" placeholder="Enter name"> <p>Hello, {{ username }}!</p> <!-- Updates as you type --> -
v-if/v-else: Conditionally render elements (adds/removes from DOM).<p v-if="isLoggedIn">Welcome back!</p> <p v-else>Please log in.</p> -
v-for: Render a list from an array.<ul> <li v-for="(item, index) in items" :key="index"> {{ index + 1 }}. {{ item }} </li> </ul> <script> export default { data() { return { items: ["Apple", "Banana", "Cherry"] }; } }; </script>Note: Always use
:keywithv-forfor performance (unique IDs are better than indexes). -
v-on: Listen to DOM events (shorthand:@).<button v-on:click="incrementCount">Click me</button> <!-- Shorthand: <button @click="incrementCount"> --> <p>Count: {{ count }}</p> <script> export default { data() { return { count: 0 }; }, methods: { incrementCount() { this.count++; } } }; </script>
3.5 Components: Building Blocks of Vue Apps
Components are reusable Vue instances with their own template, script, and style. They make your code modular and easier to maintain.
Types of Components:
- Global Components: Available everywhere in the app.
- Local Components: Only available in the parent component that registers them.
Example: Create a Local Component
- Create
src/components/WelcomeMessage.vue:
<template>
<h2>Welcome, {{ name }}!</h2>
</template>
<script>
export default {
props: ["name"] // Accepts "name" as a prop (more on props next!)
};
</script>
<style scoped>
h2 { color: #42b983; } /* scoped: styles only apply to this component */
</style>
- Use it in
App.vue:
<template>
<div>
<WelcomeMessage name="Alice" /> <!-- Pass "name" as a prop -->
</div>
</template>
<script>
import WelcomeMessage from './components/WelcomeMessage.vue'; // Import
export default {
components: { WelcomeMessage } // Register locally
};
</script>
3.6 Props: Passing Data to Child Components
Props are custom attributes for passing data from parent to child components. They are read-only in the child (children should never modify props directly).
Prop Validation
Add validation to ensure props are of the correct type:
<script>
export default {
props: {
name: {
type: String, // Expected type
required: true, // Must be provided
default: "Guest" // Fallback if not provided
},
age: {
type: Number,
validator: (value) => value >= 0 // Custom validation
}
}
};
</script>
3.7 Events: Child-to-Parent Communication
To send data from child to parent, use $emit to trigger a custom event, and the parent listens with v-on.
Example: Child Emits an Event
In ChildComponent.vue:
<template>
<button @click="sendMessage">Send Message</button>
</template>
<script>
export default {
methods: {
sendMessage() {
this.$emit("message-sent", "Hello from child!"); // Emit event with data
}
}
};
</script>
In ParentComponent.vue:
<template>
<ChildComponent @message-sent="handleMessage" />
<p>{{ parentMessage }}</p>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: { ChildComponent },
data() { return { parentMessage: "" }; },
methods: {
handleMessage(message) {
this.parentMessage = message; // Update parent data
}
}
};
</script>
3.8 Lifecycle Hooks: Managing Component State Over Time
Vue components go through a series of lifecycle stages (e.g., created, mounted, updated, destroyed). Lifecycle hooks let you run code at specific stages.
Common Lifecycle Hooks:
created: Runs after the component is initialized (data is reactive, but DOM not mounted yet). Use for API calls.mounted: Runs after the component is mounted to the DOM (access DOM elements here).updated: Runs after data changes and the DOM updates.beforeUnmount: Runs before the component is removed from the DOM (cleanup timers/event listeners here).
Example:
<script>
export default {
data() { return { posts: [] }; },
created() {
// Fetch data when component is initialized
fetch("https://jsonplaceholder.typicode.com/posts")
.then(res => res.json())
.then(data => this.posts = data);
},
mounted() {
console.log("Component mounted to DOM!");
}
};
</script>
4. State Management with Pinia
For apps with shared state (e.g., user authentication, cart items), props and events become cumbersome. Pinia (the official successor to Vuex) is a state management library that centralizes your app’s state.
Step 1: Install Pinia
In your Vue project:
npm install pinia
Step 2: Create a Store
Stores hold state, getters (computed state), and actions (methods to modify state).
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 state
},
actions: {
increment() { this.count++; }, // Modify state
decrement() { this.count--; }
}
});
Step 3: Use the Store in a Component
In App.vue:
<template>
<p>Count: {{ counterStore.count }}</p>
<p>Double Count: {{ 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(); // Initialize store
return { counterStore };
}
};
</script>
5. Routing with Vue Router
Vue Router enables navigation between “pages” in a Vue SPA.
Step 1: Install Vue Router
npm install vue-router@4 # For Vue 3
Step 2: Set Up 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 (no # in URL)
routes
});
export default router;
Step 3: Integrate Router in main.js
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
createApp(App).use(router).mount('#app');
Step 4: Add Navigation in App.vue
<template>
<nav>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</nav>
<router-view /> <!-- Where the matched component renders -->
</template>
<style>
router-link { margin-right: 10px; text-decoration: none; }
router-link.active { color: #42b983; } /* Active link styling */
</style>
6. Building a Mini Project: Todo App
Let’s combine everything we’ve learned to build a simple todo app with:
- Components (
TodoList,TodoItem) - Props/events for communication
- Pinia for state management
- Vue Router for navigation
Step 1: Set Up the Project
Use the vue-essentials-demo project we created earlier.
Step 2: Create Todo Components
src/components/TodoItem.vue: Displays a single todo, emitsdeleteevent.src/components/TodoList.vue: Lists all todos, adds new todos.
Step 3: Add Pinia Store for Todos
Create src/stores/todoStore.js to manage todos:
import { defineStore } from 'pinia';
export const useTodoStore = defineStore('todo', {
state: () => ({ todos: [] }),
actions: {
addTodo(text) { this.todos.push({ id: Date.now(), text, done: false }); },
deleteTodo(id) { this.todos = this.todos.filter(todo => todo.id !== id); }
}
});
Step 4: Assemble the App
See the full code on GitHub (simplified for brevity).
7. Advanced Tips for Vue.js Development
- Composition API vs. Options API: Use the Composition API (with
setup()or<script setup>) for larger apps—it’s more flexible for reusing logic. - Vue DevTools: Debug your app with the Vue DevTools browser extension.
- Optimization: Use
v-onceto render elements once (no reactivity),v-memoto memoize expensive renders. - Testing: Use Vue Test Utils for component testing.
- Deployment: Host your app on Netlify, Vercel, or GitHub Pages with
npm run build(generates static files indist/).
8. References
- Official Docs: vuejs.org/guide
- Pinia Docs: pinia.vuejs.org
- Vue Router Docs: router.vuejs.org
- Vue School: vueschool.io (free/paid courses)
- Vue Mastery: vuemastery.com (in-depth tutorials)
Congratulations! You’ve gone from zero to hero with Vue.js essentials. Keep practicing, building projects, and exploring the Vue ecosystem—you’re ready to create amazing apps! 🚀