Skip to content

Complete Vue 3 Tutorial

Vue 3 is a progressive JavaScript framework for building user interfaces. This tutorial will guide you from basics to advanced concepts, helping you master Vue 3's core concepts and best practices.

What is Vue 3?

Vue 3 is the latest major version of Vue.js, bringing many important improvements and new features:

  • 🚀 Better performance - Smaller bundle size, faster rendering
  • 🔧 Composition API - More flexible logic reuse
  • 📦 Better TypeScript support - Native TypeScript support
  • 🌳 Tree-shaking friendly - Import on demand, reducing bundle size

Environment Setup

Installing Node.js

Ensure your system has Node.js 16+ installed:

bash
node --version
npm --version

Creating a Vue 3 Project

Using Vite to create a new project (recommended):

bash
npm create vue@latest my-vue-app
cd my-vue-app
npm install
npm run dev

Or using Vue CLI:

bash
npm install -g @vue/cli
vue create my-vue-app
cd my-vue-app
npm run serve

Basic Concepts

1. Template Syntax

Vue uses an HTML-based template syntax:

vue
<template>
  <div>
    <!-- Text interpolation -->
    <h1>{{ title }}</h1>
    
    <!-- Attribute binding -->
    <img :src="imageUrl" :alt="imageAlt">
    
    <!-- Event listening -->
    <button @click="handleClick">Click me</button>
    
    <!-- Conditional rendering -->
    <p v-if="isVisible">This text is visible</p>
    
    <!-- List rendering -->
    <ul>
      <li v-for="item in items" :key="item.id">
        {{ item.name }}
      </li>
    </ul>
  </div>
</template>

2. Reactive Data

Using ref and reactive to create reactive data:

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

// Use ref for primitive types
const count = ref(0)
const message = ref('Hello Vue 3!')

// Use reactive for object types
const user = reactive({
  name: 'John',
  age: 25,
  email: 'john@example.com'
})

// Modifying data
const increment = () => {
  count.value++
}

const updateUser = () => {
  user.name = 'Jane'
  user.age = 30
}
</script>

3. Computed Properties

Using computed to create computed properties:

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

const firstName = ref('John')
const lastName = ref('Doe')

// Read-only computed property
const fullName = computed(() => {
  return firstName.value + ' ' + lastName.value
})

// Writable computed property
const fullNameWritable = computed({
  get() {
    return firstName.value + ' ' + lastName.value
  },
  set(newValue) {
    [firstName.value, lastName.value] = newValue.split(' ')
  }
})
</script>

4. Watchers

Using watch and watchEffect to watch for data changes:

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

const count = ref(0)
const user = reactive({ name: 'John', age: 25 })

// Watching a single data source
watch(count, (newValue, oldValue) => {
  console.log(`count changed from ${oldValue} to ${newValue}`)
})

// Watching multiple data sources
watch([count, () => user.name], ([newCount, newName], [oldCount, oldName]) => {
  console.log('count or user.name changed')
})

// Immediate watcher
watchEffect(() => {
  console.log(`Current count: ${count.value}`)
})
</script>

Component Development

1. Component Definition

vue
<!-- UserCard.vue -->
<template>
  <div class="user-card">
    <img :src="user.avatar" :alt="user.name">
    <h3>{{ user.name }}</h3>
    <p>{{ user.email }}</p>
    <button @click="$emit('follow', user.id)">Follow</button>
  </div>
</template>

<script setup>
// Define props
const props = defineProps({
  user: {
    type: Object,
    required: true
  }
})

// Define emits
const emit = defineEmits(['follow'])
</script>

<style scoped>
.user-card {
  border: 1px solid #ddd;
  border-radius: 8px;
  padding: 16px;
  text-align: center;
}
</style>

2. Using Components

vue
<template>
  <div>
    <UserCard 
      v-for="user in users" 
      :key="user.id"
      :user="user"
      @follow="handleFollow"
    />
  </div>
</template>

<script setup>
import UserCard from './components/UserCard.vue'

const users = ref([
  { id: 1, name: 'John', email: 'john@example.com', avatar: '/avatar1.svg' },
  { id: 2, name: 'Jane', email: 'jane@example.com', avatar: '/avatar2.svg' }
])

const handleFollow = (userId) => {
  console.log(`Following user ${userId}`)
}
</script>

3. Slots

vue
<!-- Card.vue -->
<template>
  <div class="card">
    <header class="card-header">
      <slot name="header"></slot>
    </header>
    <main class="card-content">
      <slot></slot>
    </main>
    <footer class="card-footer">
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

Using slots:

vue
<template>
  <Card>
    <template #header>
      <h2>Card Title</h2>
    </template>
    
    <p>This is the main content of the card</p>
    
    <template #footer>
      <button>Confirm</button>
      <button>Cancel</button>
    </template>
  </Card>
</template>

State Management

Using Pinia

Installing Pinia:

bash
npm install pinia

Creating a store:

javascript
// stores/user.js
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', () => {
  const user = ref(null)
  const isLoggedIn = computed(() => !!user.value)
  
  const login = async (credentials) => {
    // Login logic
    const response = await api.login(credentials)
    user.value = response.data
  }
  
  const logout = () => {
    user.value = null
  }
  
  return {
    user,
    isLoggedIn,
    login,
    logout
  }
})

Using in components:

vue
<script setup>
import { useUserStore } from '@/stores/user'

const userStore = useUserStore()

const handleLogin = async () => {
  await userStore.login({
    username: 'admin',
    password: '123456'
  })
}
</script>

Routing

Using Vue Router

Installing Vue Router:

bash
npm install vue-router@4

Configuring routes:

javascript
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home.vue'
import About from '@/views/About.vue'

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
  { path: '/user/:id', component: User, props: true }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

export default router

Using in components:

vue
<template>
  <nav>
    <router-link to="/">Home</router-link>
    <router-link to="/about">About</router-link>
  </nav>
  <router-view />
</template>

<script setup>
import { useRouter, useRoute } from 'vue-router'

const router = useRouter()
const route = useRoute()

const goToUser = (userId) => {
  router.push(`/user/${userId}`)
}
</script>

Best Practices

1. Component Design Principles

  • Single Responsibility: Each component should be responsible for one feature
  • Reusability: Design generic component interfaces
  • Testability: Write unit tests

2. Performance Optimization

vue
<script setup>
import { defineAsyncComponent } from 'vue'

// Async component
const AsyncComponent = defineAsyncComponent(() => 
  import('./components/HeavyComponent.vue')
)

// Using shallowRef for large objects
import { shallowRef } from 'vue'
const largeData = shallowRef({})
</script>

3. Code Organization

src/
├── components/          # Common components
│   ├── ui/             # UI components
│   └── business/       # Business components
├── views/              # Page components
├── stores/             # State management
├── composables/        # Composition functions
├── utils/              # Utility functions
└── assets/             # Static assets

Common Questions

Q: When should I use ref and when should I use reactive?

A:

  • Use ref for primitive types (string, number, boolean)
  • Use reactive for objects and arrays
  • Use ref when you need to reassign the entire object

Q: How do I use TypeScript with Vue 3?

A:

vue
<script setup lang="ts">
interface User {
  id: number
  name: string
  email: string
}

const user = ref<User>({
  id: 1,
  name: 'John',
  email: 'john@example.com'
})
</script>

Q: How do I optimize large list rendering?

A: Use virtual scrolling or pagination to avoid rendering too many DOM elements at once.

Summary

Vue 3 provides a powerful and flexible development experience, with the Composition API and improved performance allowing us to build better applications. By mastering these core concepts and best practices, you'll be able to efficiently develop Vue 3 applications.


Continue learning:

VitePress Development Guide