Components và Props

65 phút

Components và Props

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