📖 Vue.js Toàn tập - Components và Props
65 phút

Components và Props

Giới thiệu Components

Components cho phép chia nhỏ UI thành các phần tái sử dụng.

Đăng ký Components

Global Components

// main.js
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

app.component('MyComponent', {
  template: '<div>My Global Component</div>'
})

app.mount('#app')

Local Components

<script>
import ChildComponent from './ChildComponent.vue'

export default {
  components: {
    ChildComponent
  }
}
</script>

Props

Định nghĩa Props

<!-- ChildComponent.vue -->
<template>
  <div class="user-card">
    <h3>{{ name }}</h3>
    <p>Email: {{ email }}</p>
    <p>Tuổi: {{ age }}</p>
    <p v-if="isAdmin">Quản trị viên</p>
  </div>
</template>

<script>
export default {
  props: {
    name: {
      type: String,
      required: true
    },
    email: {
      type: String,
      default: 'No email provided'
    },
    age: {
      type: Number,
      validator: (value) => value >= 0
    },
    isAdmin: {
      type: Boolean,
      default: false
    }
  }
}
</script>

Truyền Props

<!-- ParentComponent.vue -->
<template>
  <div>
    <user-card 
      name="John Doe"
      email="john@example.com"
      :age="25"
      :is-admin="true"
    />
    <user-card 
      name="Jane Smith"
      :age="30"
    />
  </div>
</template>

Slots

Default Slot

<!-- BaseLayout.vue -->
<template>
  <div class="container">
    <header>
      <slot name="header"></slot>
    </header>
    <main>
      <slot></slot>
    </main>
    <footer>
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

Sử dụng Slots

<template>
  <base-layout>
    <template #header>
      <h1>Tiêu đề trang</h1>
    </template>
    
    <p>Nội dung chính của trang</p>
    
    <template #footer>
      <p>Bản quyền 2024</p>
    </template>
  </base-layout>
</template>

Emits (Custom Events)

Định nghĩa Emits

<!-- TodoItem.vue -->
<template>
  <div class="todo-item">
    <span :class="{ completed: todo.completed }">
      {{ todo.text }}
    </span>
    <button @click="$emit('toggle', todo.id)">
      {{ todo.completed ? 'Hoàn tác' : 'Hoàn thành' }}
    </button>
    <button @click="$emit('delete', todo.id)">Xóa</button>
  </div>
</template>

<script>
export default {
  props: {
    todo: {
      type: Object,
      required: true
    }
  },
  emits: ['toggle', 'delete']
}
</script>

Sử dụng Emits

<template>
  <div>
    <todo-item 
      v-for="todo in todos"
      :key="todo.id"
      :todo="todo"
      @toggle="toggleTodo"
      @delete="removeTodo"
    />
  </div>
</template>

Provide/Inject

Provide từ Component cha

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

const user = ref({
  name: 'John Doe',
  role: 'admin'
})

const updateUser = (newUser) => {
  user.value = { ...user.value, ...newUser }
}

provide('user', {
  user,
  updateUser
})
</script>

Inject từ Component con

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

const { user, updateUser } = inject('user')

const changeName = () => {
  updateUser({ name: 'Jane Smith' })
}
</script>

📝 Bài tập (1)

  1. Tạo các components tái sử dụng: Button, Card, Modal

Tiến độ khóa học
Bài học "Components và Props" - Khóa học "Vue.js Toàn tập"