Phát triển ứng dụng Vue theo mô hình component giúp chia nhỏ chức năng phức tạp thành các khối độc lập, giảm sự phụ thuộc và tăng khả năng bảo trì. Các component được phân loại thành:
- Component trình diễn: Chỉ hiển thị dữ liệu nhận vào, không xử lý logic (càng ở tầng dưới càng đơn giản)
- Component điều khiển: Xử lý nghiệp vụ chính, quản lý luồng dữ liệu (thường ở tầng trên)
Lợi ích chính khi áp dụng component hóa:
- Tăng tốc độ phát triển
- Khả năng tái sử dụng cao
- Phối hợp nhóm hiệu quả
- Quản lý và mở rộng dễ dàng
Quy tắc khai báo component
Vue.component('product-list', {
template: `<div>Nội dung component</div>`
})
Cách đặt tên:
- Dạng kebab-case:
product-list(ưu tiên trong template HTML) - Dạng PascalCase:
ProductList
Lưu ý quan trọng:
- Khởi tạo trước khi tạo instance Vue chính
- Tên component phải khớp khi sử dụng
- Template chỉ có một root element
- Trong component,
dataphải là hàm trả về object
Truyền dữ liệu từ cha xuống con
Sử dụng thuộc tính tùy chỉnh với v-bind:
<product-list :items="productData"></product-list>
Component con nhận dữ liệu qua props:
props: {
items: {
type: Array,
required: true,
default: () => []
}
}
Ví dụ minh họa:
<div id="app">
<product-list :items="products"></product-list>
</div>
const ProductCatalog = {
props: {
items: {
type: Array,
default: () => []
}
},
template: `
<ul>
<li v-for="product in items" :key="product.id">
{{ product.name }} - ${{ product.price }}
</li>
</ul>
`
}
Vue.component('product-list', ProductCatalog)
new Vue({
el: '#app',
data: {
products: [
{ id: 1, name: 'Laptop', price: 999 },
{ id: 2, name: 'Phone', price: 699 }
]
}
})
Truyền dữ liệu từ con lên cha
Component cha lắng nghe sự kiện tùy chỉnh:
<product-list
:items="products"
@stock-update="handleStockChange"
></product-list>
Component con kích hoạt sự kiện qua $emit:
methods: {
updateStock(id, inStock) {
this.$emit('stock-update', id, inStock)
}
}
Nguyên tắc quan trọng: Dữ liệu chỉ truyền một chiều từ cha xuống con. Component con không được trực tiếp sửa dữ liệu từ cha, mà phải thông báo qua sự kiện để cha cập nhật.
Ví dụ hoàn chỉnh với checkbox
<div id="app">
<input v-model="newProduct" @keyup.enter="addProduct">
<product-inventory
:products="inventory"
@toggle-stock="updateStockStatus"
></product-inventory>
</div>
const InventoryManager = {
props: {
products: {
type: Array,
default: () => []
}
},
template: `
<div>
<ul>
<li v-for="item in products" :key="item.id">
<input
type="checkbox"
:checked="item.inStock"
@change="toggleStock(item.id, $event)"
>
{{ item.name }}
</li>
</ul>
</div>
`,
methods: {
toggleStock(id, event) {
this.$emit('toggle-stock', id, event.target.checked)
}
}
}
Vue.component('product-inventory', InventoryManager)
new Vue({
el: '#app',
data: {
newProduct: '',
inventory: [
{ id: 101, name: 'Keyboard', inStock: true },
{ id: 102, name: 'Mouse', inStock: false }
]
},
methods: {
addProduct() {
this.inventory.push({
id: Date.now(),
name: this.newProduct,
inStock: true
})
this.newProduct = ''
},
updateStockStatus(id, status) {
const product = this.inventory.find(p => p.id === id)
if (product) product.inStock = status
}
}
})
Xử lý dữ liệu tham chiếu
Khi cần chỉnh sửa dữ liệu phức tạp, component con nên tạo bản sao riêng:
data() {
return {
localProducts: JSON.parse(JSON.stringify(this.products))
}
}
Cách này tránh ảnh hưởng trực tiếp đến dữ liệu gốc từ component cha, đặc biệt quan trọng với object và array.