Tìm hiểu về Component trong Vue.js: Ví dụ, Tái Sử Dụng và Tổ Chức

Component (thành phần) là một khái niệm cốt lõi trong Vue.js, cho phép bạn xây dựng các giao diện người dùng phức tạp bằng cách chia nhỏ chúng thành các phần nhỏ hơn, có thể tái sử dụng và dễ quản lý. Bài viết này sẽ đi sâu vào component trong Vue.js, từ những ví dụ cơ bản đến cách tái sử dụng, tổ chức và truyền dữ liệu giữa các component.

Ví dụ cơ bản về Component trong Vue.js

Component trong Vue.js là các đối tượng Vue có thể tái sử dụng. Hãy xem xét ví dụ sau:


Ví dụ Component

Trong ví dụ này, <button-counter> là tên của component. Chúng ta có thể sử dụng component này như một phần tử trong đối tượng Vue gốc:

Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    }
  },
  template: 'Bấm vào tôi {{ count }} lần.'
})

new Vue({
  el: '#example'
})

Vì component là các đối tượng Vue tái sử dụng, chúng cũng chấp nhận các tùy chọn như data, computed, watch, methods và các hook vòng đời. Tuy nhiên, có một vài ngoại lệ, chẳng hạn như tùy chọn el, chỉ dành cho đối tượng Vue gốc.

Tái sử dụng Component: Xây dựng giao diện linh hoạt

Một trong những lợi ích lớn nhất của component là khả năng tái sử dụng. Bạn có thể sử dụng một component nhiều lần trong ứng dụng của mình:

Mỗi khi bạn sử dụng một component, một đối tượng mới của component đó sẽ được tạo. Điều này có nghĩa là mỗi component sẽ giữ một giá trị count riêng biệt.

Ví dụ về tái sử dụng component trong Vue.jsVí dụ về tái sử dụng component trong Vue.js

Điều quan trọng cần lưu ý là tùy chọn data của component phải là một hàm. Điều này đảm bảo rằng mỗi đối tượng component có một bản sao riêng biệt của đối tượng data được trả về:

data: function () {
  return {
    count: 0
  }
}

Nếu data là một object, tất cả các component sẽ chia sẻ cùng một object, dẫn đến các hành vi không mong muốn.

Tổ chức Component: Xây dựng ứng dụng có cấu trúc

Một ứng dụng Vue.js thường được tổ chức dưới dạng một cây component lồng nhau. Ví dụ, bạn có thể có các component cho header, sidebarcontent, mỗi component này lại chứa các component con cho menu, blog-post, v.v.

Để có thể sử dụng trong các template, component phải được đăng ký. Có hai cách đăng ký component: toàn cụccục bộ.

Component đăng ký ở cấp toàn cục có thể được sử dụng trong template của bất kỳ đối tượng Vue gốc (new Vue) nào được tạo ra sau đó – và trong tất cả các component con trên cây component của đối tượng đó. Ví dụ: Vue.component('button-counter', ...) đăng ký component button-counter trên toàn cục.

Truyền dữ liệu xuống Component con bằng Prop

Để component thực sự hữu ích, chúng ta cần có cách để truyền dữ liệu vào chúng. Đó là lúc prop phát huy tác dụng.

Prop là các thuộc tính tùy chỉnh mà bạn có thể đăng ký trên một component. Khi một giá trị được truyền vào một prop, nó sẽ trở thành một “prop-erty” của đối tượng component đó. Để truyền tiêu đề (title) vào component blog-post, chúng ta sử dụng tùy chọn props:

Vue.component('blog-post', {
  props: ['title'],
  template: '

{{ title }}

'
})

Một component có thể có bao nhiêu prop tùy ý và prop có thể nhận bất kỳ giá trị gì. Trong template, bạn có thể truy xuất giá trị này trên đối tượng component, giống như với data.

Sau khi prop đã được đăng ký, bạn có thể truyền dữ liệu vào như một thuộc tính tùy chỉnh:

Trong một ứng dụng điển hình, bạn có thể có một mảng các bài viết trong data:

data: {
  posts: [
    { id: 1, title: 'Giới thiệu về Vue.js', content: '...' },
    { id: 2, title: 'Các khái niệm cơ bản trong Vue.js', content: '...' }
  ]
}

và sau đó render một component cho mỗi bài viết:


Ở đây, chúng ta sử dụng v-bind để truyền động prop. Cách làm này đặc biệt hữu ích khi bạn không biết trước được chính xác nội dung bạn sẽ render.

Một phần tử gốc đơn lập: Cấu trúc template hợp lệ

Khi xây dựng component blog-post, template của bạn có thể chứa nhiều thứ hơn là chỉ mỗi title. Ít nhất bạn cũng sẽ có thêm nội dung bài viết:


  {{ title }}
  {{ content }}

Tuy nhiên, nếu bạn sử dụng template này, Vue sẽ thông báo lỗi “Component template should contain exactly one root element” (template của component phải chứa chính xác một phần tử gốc). Bạn có thể sửa lỗi này bằng cách bọc template trong một phần tử cha, ví dụ:


    {{ title }}
    {{ content }}

Gửi thông tin đến đối tượng cha bằng Sự kiện

Trong nhiều trường hợp, component con cần giao tiếp ngược lên đối tượng cha. Ví dụ, chúng ta muốn thêm tính năng phóng to font chữ của bài viết, nhưng vẫn giữ nguyên các thành phần khác trên trang.

Chúng ta có thể hỗ trợ tính năng này bằng cách thêm thuộc tính postFontSize trong data của đối tượng cha:

data: {
  postFontSize: 1
}

Thuộc tính này có thể được dùng trong template để quản lý cỡ chữ của tất cả các bài viết:



  {{ post.title }}
  {{ post.content }}

Bây giờ, hãy thêm một nút để tăng cỡ chữ ngay trước nội dung của mỗi bài viết:


    Phóng to
    {{ title }}
    {{ content }}

Khi nút “Phóng to” được bấm, chúng ta muốn yêu cầu đối tượng cha phóng to cỡ chữ của tất cả các bài viết. Để phát ra (emit) một sự kiện, chúng ta có thể gọi phương thức $emit cho sẵn và truyền vào tên của sự kiện:

methods: {
  enlargeText: function () {
    this.$emit('enlarge-text')
  }
}

Sau đó, trong component cha, chúng ta có thể lắng nghe sự kiện này bằng v-on giống như với các sự kiện DOM:



  {{ post.title }}
  {{ post.content }}
methods: {
  onEnlargeText: function (enlargeAmount) {
    this.postFontSize += enlargeAmount
  }
}

Phân phối nội dung với Slot

Giống như các phần tử HTML, việc có thể truyền nội dung vào một component thường rất hữu ích, ví dụ:


  Nội dung ở đây

có thể render thành:



  Nội dung ở đây

Việc này rất đơn giản với phần tử tùy biến “ của Vue:



Như bạn thấy, chúng ta chỉ cần thêm “ vào nơi cần thể hiện nội dung.

Component động: Linh hoạt trong hiển thị

Đôi khi, bạn muốn chuyển qua lại giữa các component, ví dụ như trên một giao diện tab:



    Tab 1
    Tab 2

Ví dụ trên hoạt động nhờ thuộc tính đặc biệt is của một component trong Vue:

data: {
  currentTab: 'tab-1',
  tabs: ['tab-1', 'tab-2']
},
components: {
  'tab-1': { template: '<div>Nội dung tab 1</div>' },
  'tab-2': { template: '<div>Nội dung tab 2</div>' }
}

Trong ví dụ trên, currentTabComponent có thể chứa:

  • Tên của một component đã được đăng ký, hoặc
  • Object chứa các tùy chọn của một component

Kết luận

Component là một công cụ mạnh mẽ trong Vue.js, cho phép bạn xây dựng các ứng dụng phức tạp một cách dễ dàng và hiệu quả. Bằng cách hiểu rõ các khái niệm cơ bản về component, bạn có thể tận dụng tối đa sức mạnh của Vue.js để tạo ra các giao diện người dùng tuyệt vời.