Học Vue.js 3 cơ bản – Bài 2: Components

Trong Vue, Component là “khối xây dựng” của ứng dụng. Thay vì viết tất cả trong App.vue, chúng ta tách thành nhiều component nhỏ có thể tái sử dụng.


1. Tạo Component

Giả sử bạn muốn tạo 1 component hiển thị thông tin người dùng.

📂 Cấu trúc thư mục:

src/
┣ components/
┃ ┗ UserCard.vue
┣ App.vue
main.js

UserCard.vue

<script setup>
defineProps({
name: String,
age: Number
})
</script>

<template>
<div class="card">
<h3>{{ name }}</h3>
<p>Tuổi: {{ age }}</p>
</div>
</template>

<style scoped>
.card {
padding: 10px;
border: 1px solid #ddd;
margin-bottom: 10px;
border-radius: 8px;
}
</style>

App.vue

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

<template>
<h1>Danh sách người dùng</h1>
<UserCard name="Thanh" :age="25" />
<UserCard name="Lan" :age="22" />
</template>


2. Props – Truyền dữ liệu từ Cha → Con

  • Dùng defineProps() trong Composition API.

  • Props có thể ràng buộc kiểu dữ liệu (String, Number, Boolean, Array, Object…).

Ví dụ:

<!-- Cha -->
<UserCard name="Minh" :age="30" />

Trong UserCard.vue:

<script setup>
defineProps({
name: {
type: String,
required: true
},
age: {
type: Number,
default: 18
}
})
</script>

3. Emit – Gửi sự kiện từ Con → Cha

Ví dụ: Nút “Xóa user” trong component con, khi click sẽ báo cho cha biết.

UserCard.vue

<script setup>
const emit = defineEmits(['delete'])

defineProps({
name: String,
age: Number
})

function handleDelete() {
emit('delete', name) // gửi sự kiện + dữ liệu name
}
</script>

<template>
<div class="card">
<h3>{{ name }}</h3>
<p>Tuổi: {{ age }}</p>
<button @click="handleDelete">Xóa</button>
</div>
</template>

App.vue

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

const users = ref([
{ name: 'Thanh', age: 25 },
{ name: 'Lan', age: 22 },
{ name: 'Minh', age: 30 }
])

function removeUser(name) {
users.value = users.value.filter(u => u.name !== name)
}
</script>

<template>
<h1>Danh sách người dùng</h1>
<UserCard
v-for="u in users"
:key="u.name"
:name="u.name"
:age="u.age"
@delete="removeUser"
/>
</template>


4. Slot – Nội dung động trong Component

Slot giúp bạn chèn nội dung từ cha vào component con.

Card.vue

<template>
<div class="card">
<slot></slot> <!-- nơi nội dung được chèn vào -->
</div>
</template>

<style scoped>
.card {
border: 1px solid #ccc;
padding: 15px;
margin: 10px 0;
border-radius: 6px;
}
</style>

App.vue

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

<template>
<Card>
<h3>Tiêu đề A</h3>
<p>Nội dung A</p>
</Card>

<Card>
<h3>Tiêu đề B</h3>
<p>Nội dung B</p>
</Card>
</template>

👉 Ngoài ra còn có Named slot:

<slot name="header"></slot>
<slot></slot> <!-- default -->
<slot name="footer"></slot>

5. Lifecycle Hooks

Vue cung cấp các hook trong vòng đời component.

Ví dụ: log khi component được mount.

UserCard.vue

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

defineProps({ name: String })

onMounted(() => {
console.log(`UserCard [${name}] đã mount`)
})

onUpdated(() => {
console.log(`UserCard [${name}] đã update`)
})

onUnmounted(() => {
console.log(`UserCard [${name}] đã destroy`)
})
</script>

<template>
<div>
<h3>{{ name }}</h3>
</div>
</template>


🎯 Kết luận

Trong bài này bạn đã học:

  • Cách tạo component trong Vue

  • Props (cha → con)

  • Emit (con → cha)

  • Slot & Named slot

  • Lifecycle hooks (onMounted, onUpdated, onUnmounted)