💚 Vue.js — Zero to Hero

The progressive JavaScript framework — approachable, performant, versatile

💚 What is Vue.js?

Vue is a progressive JavaScript framework for building UIs. It's designed to be adoptable incrementally — use it for a widget or build a full SPA.

📄 SFC

Single File Components keep template, script, and style in one .vue file.

🔄 Reactivity

Vue's reactivity system automatically tracks and updates the DOM.

🧩 Composition API

Modern, flexible way to organize component logic.

🌍 Ecosystem

Pinia for state, Vue Router for routing, Nuxt for SSR.

⚙️ Setup

# Create new Vue app (Vite)
npm create vue@latest my-app
cd my-app
npm install
npm run dev   # → http://localhost:5173

Project structure:

my-app/
├── src/
│   ├── App.vue          # Root component
│   ├── main.js          # Entry point
│   ├── components/      # Reusable components
│   ├── views/           # Page components
│   └── stores/          # Pinia stores
└── vite.config.js

📄 Single File Component (SFC)

Every .vue file has three blocks: <template>, <script>, and <style>.

<template>
  <div class="card">
    <h1>{{ title }}</h1>
    <p>{{ description }}</p>
  </div>
</template>

<script setup>
const title = 'Hello Vue!';
const description = 'This is my first component';
</script>

<style scoped>  /* scoped = only this component */
.card { padding: 1rem; border-radius: 8px; }
</style>

🔄 Reactivity — ref & reactive

<script setup>
import { ref, reactive } from 'vue';

// ref — for primitives
const count = ref(0);
const name  = ref('Alice');

// reactive — for objects
const user = reactive({
  name: 'Bob',
  age:  25,
});

function increment() {
  count.value++;         // use .value in script
  user.age++;
}
</script>

<template>
  <p>{{ count }}</p>  <!-- no .value in template -->
  <button @click="increment">+</button>
</template>

🧮 Computed Properties

<script setup>
import { ref, computed } from 'vue';

const price    = ref(100);
const quantity = ref(3);

// Auto-recalculates when price or quantity changes
const total = computed(() => price.value * quantity.value);

const items = ref(['apple', 'banana', 'cherry']);
const filtered = computed(() =>
  items.value.filter(i => i.includes('a'))
);
</script>

<template>
  <p>Total: ${{ total }}</p>
</template>

👁 Watchers

<script setup>
import { ref, watch, watchEffect } from 'vue';

const search = ref('');

// watch — specific source
watch(search, (newVal, oldVal) => {
  console.log('Search changed:', newVal);
});

// watchEffect — auto-tracks dependencies
watchEffect(() => {
  console.log('Current search:', search.value);
});
</script>

🏷 Template Directives

DirectivePurpose
v-if / v-elseConditional rendering
v-showToggle visibility (CSS display)
v-forLoop over arrays/objects
v-modelTwo-way data binding
v-bind / :Bind attribute dynamically
v-on / @Listen to events
<template>
  <p v-if="isLoggedIn">Welcome back!</p>
  <p v-else>Please log in</p>

  <li v-for="item in items" :key="item.id">{{ item.name }}</li>

  <input v-model="search" />       <!-- two-way bind -->
  <img   :src="imageUrl"  />       <!-- dynamic attr -->
  <button @click="doSomething">Go</button>
</template>

🖱 Events

<template>
  <!-- Modifiers -->
  <form @submit.prevent="onSubmit">    <!-- preventDefault -->
  <a    @click.stop="onClick">           <!-- stopPropagation -->
  <input @keyup.enter="onEnter" />    <!-- key filter -->
  <button @click.once="onClick">      <!-- fire once -->
</template>

📨 Props & Emits

<!-- Child.vue -->
<script setup>
const props = defineProps({
  title:    { type: String,  required: true },
  count:    { type: Number,  default: 0 },
  active:   { type: Boolean, default: false },
});

const emit = defineEmits(['update', 'close']);

function handleClick() {
  emit('update', props.count + 1);
}
</script>

<!-- Parent.vue -->
<Child :title="'Hello'" :count="num" @update="num = $event" />

♻️ Lifecycle Hooks

<script setup>
import { onMounted, onUpdated, onUnmounted, onBeforeMount } from 'vue';

onMounted(()   => console.log('Component mounted'));    // ← most common
onUpdated(()   => console.log('Component updated'));
onUnmounted(() => console.log('Component destroyed'));   // cleanup here
</script>

🧩 Composables

Composables are reusable functions that use Vue's reactivity — like React custom hooks.

// composables/useFetch.js
import { ref } from 'vue';

export function useFetch(url) {
  const data    = ref(null);
  const loading = ref(true);
  const error   = ref(null);

  fetch(url)
    .then(r => r.json())
    .then(d => data.value = d)
    .catch(e => error.value = e)
    .finally(() => loading.value = false);

  return { data, loading, error };
}

// Usage in any component
const { data, loading } = useFetch('/api/users');

🍍 Pinia (State Management)

# Install
npm install pinia
// stores/counter.js
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0);
  const double = computed(() => count.value * 2);
  function increment() { count.value++; }
  return { count, double, increment };
});

// Use in any component
<script setup>
const counter = useCounterStore();
</script>
<template>
  <p>{{ counter.count }}</p>
  <button @click="counter.increment">+</button>
</template>

🔗 Vue Router

# Install
npm install vue-router
// router/index.js
import { createRouter, createWebHistory } from 'vue-router';

const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/',        component: () => import('../views/Home.vue') },
    { path: '/about',   component: () => import('../views/About.vue') },
    { path: '/post/:id', component: () => import('../views/Post.vue') },
  ],
});

// In a component
import { useRouter, useRoute } from 'vue-router';
const router = useRouter();
const route  = useRoute();
console.log(route.params.id);
router.push('/about');

🚀 Pro Tips

<!-- v-model on custom components -->
<MyInput v-model="username" />

<!-- Slots — pass template content to child -->
<Card>
  <template #header><h2>Title</h2></template>
  <p>Body content here</p>
</Card>

<!-- Teleport — render outside current DOM tree -->
<Teleport to="body">
  <Modal v-if="showModal" />
</Teleport>

<!-- Transition animation -->
<Transition name="fade">
  <p v-if="show">Fades in/out</p>
</Transition>
🎉 You now know Vue.js! Next steps: learn Nuxt.js for SSR/SSG, Pinia for complex state, and the Vueuse library for useful composables.