Bài 2: Components

Bài 2: Components

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)

👉 Đây là nền tảng để sang Bài 3 – Composition API (setup, ref, reactive, computed, watch, provide/inject, composables).