- Học Vue
-
Hệ sinh thái
Hỗ trợ
Công cụ
Thư viện chính thức
Tin tức
Tài nguyên
- Đội ngũ
- Hỗ trợ Vue
- Ngôn ngữ
Hướng dẫn
Khái niệm cơ bản
- Cài đặt
- Giới thiệu
- Đối tượng Vue
- Cú pháp template
- Computed property và watcher
- Binding cho class và style
- Render theo điều kiện
- Render danh sách
- Xử lí sự kiện
- Ràng buộc form input
- Cơ bản về component
Components In-Depth
- Đăng kí Component
- Props
- Custom Events
- Slots
- Dynamic & Async Components
- Handling Edge Cases
Hiệu ứng chuyển động
- Transition cho enter/leave & danh sách
- Transition cho trạng thái
Tái sử dụng & kết hợp
- Mixin
- Directive tùy biến
- Các hàm render & JSX
- Plugin
- Filter
Công cụ
- Triển khai cho môi trường production
- Single File Components
- Unit test
- TypeScript Support
Mở rộng quy mô ứng dụng
- Routing
- Quản lí trạng thái
- Render ở phía server
Bên trong Vue
- Reactivity in Depth
Thông tin thêm
- Comparison with Other Frameworks
- Join the Vue.js Community!
- Đội ngũ
Cơ bản về component
Ví dụ cơ bản
Đây là ví dụ về một component trong Vue:
// Định nghĩa một component với tên là "button-counter" |
Component là các đối tượng Vue có thể sử dụng lại được với một cái tên: trong trường hợp này là <button-counter>
. Chúng ta có thể dùng component này như là một phần tử bên trong đối tượng Vue gốc được tạo bởi new Vue
:
<div id="components-demo"> |
new Vue({ el: '#components-demo' }) |
Vì là những đối tượng Vue tái sử dụng được, các component cùng nhận các tùy chọn như new Vue
, ví dụ data
, computed
, watch
, methods
, và các hook vòng đời. Các ngoại lệ duy nhất là một số ít tùy chọn đặc biệt cho root như el
.
Tái sử dụng component
Bạn có thể tái sử dụng component bao nhiêu lần tùy ý:
<div id="components-demo"> |
Để ý là khi bấm các nút trên đây, mỗi nút giữ một giá trị count
riêng hoàn toàn tách biệt. Điều này là vì mỗi khi bạn dùng một component, một đối tượng của component đó được tạo mới.
data
phải là một hàm
Bạn có thể cũng đã để ý thấy rằng khi định nghĩa component <button-counter>
, chúng ta không truyền thẳng một object vào data
như thế này:
data: { |
Thay vào đó, tùy chọn data
của component phải là một hàm. Bằng cách này, mỗi đối tượng của component có thể duy trì một bản sao riêng biệt của đối tượng data được trả về:
data: function () { |
Nếu Vue không có quy tắc này, bấm một nút sẽ ảnh hưởng đến dữ liệu của toàn bộ các đối tượng khác, như thế này:
Tổ chức component
Một ứng dụng 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, sidebar, khu vực nội dung, mỗi component này lại chứa các component dành cho trình đơn, blog post, vân vân.
Để có thể được sử dụng trong các template, component phải được đăng kí. Có hai cách đăng kí component: toàn cục và cục bộ. Trên đây chúng ta chỉ mới đăng kí component ở cấp toàn cục với Vue.component
:
Vue.component('my-component-name', { |
Component đăng kí ở cấp toàn cục có thể được 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 đó.
Hiện giờ thì đó là tất cả những gì bạn cần biết về đăng kí component, nhưng sau khi đọc xong trang này và hiểu thêm về component, bạn nên quay lại và đọc bản hướng dẫn đầy đủ về đăng kí component.
Truyền dữ liệu xuống component con bằng prop
Trên đây chúng ta có nhắc đến việc tạo component cho các bài viết trên blog. Vấn đề là, component không có ích gì nếu không có dữ liệu truyền vào, ví dụ tựa đề và nội dung của bài đăng. Đó là lúc chúng ta cần đến prop.
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ó trở thành một “_prop_erty” của đối tượng component đó. Để truyền tựa đề (title
) vào component bài viết (blog-post
), chúng ta sử dụng tùy chọn props
:
Vue.component('blog-post', { |
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 trên đây, bạn có thể thấy là chúng ta có thể truy xuất giá trị này trên đối tượng component, giống như với data
.
Một 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, ví dụ:
<blog-post title="Giới thiệu về Vue"></blog-post> |
Tuy nhiên, trong một ứng dụng điển hình, bạn có lẽ sẽ có một mảng các bài viết trong data
:
new Vue({ |
và sau đó render một component cho mỗi bài viết:
<blog-post |
Trên đây, bạn có thể thấy là chúng ta 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, như khi lấy bài viết từ một API.
Hiện giờ thì đó là tất cả những gì bạn cần biết về prop, nhưng sau khi đọc xong trang này và hiểu thêm về component, bạn nên quay lại và đọc bản hướng dẫn đầy đủ về props.
Một phần tử gốc đơn lập
Khi xây dựng component <blog-post>
cho bài viết, thế nào rồi template của bạn cũng sẽ chứa nhiều thứ hơn là mỗi title
. Ít nhất bạn cũng sẽ có thêm nội dung bài viết:
<h3>{{ post.title }}</h3> |
Nhưng nếu bạn sử dụng template này, Vue sẽ thông báo lỗi every component must have a single root element (mỗi component phải có một phần tử gốc đơn lập). 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ụ:
<div class="blog-post"> |
Gửi thông tin đến đối tượng cha bằng sự kiện
Khi xây dựng component <blog-post>
, một số tính năng có thể 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 mà 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:
new Vue({ |
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:
<div id="blog-posts-events-demo"> |
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:
Vue.component('blog-post', { |
Ví dụ trên đây và một số ví dụ tiếp theo sử dụng template literal để giúp template nhiều dòng dễ đọc hơn. Tính năng này không hoạt động trên Internet Explorer (IE), vì thế nếu phải hỗ trợ IE và không sử dụng các thư viện hoặc ngôn ngữ biên dịch (như Babel hoặc TypeScript), bạn có thể dùng dấu chéo ngược thay thế.
Tuy nhiên, nút này hiện không làm gì cả:
<button> |
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. May thay, các đối tượng Vue cung cấp một hệ thống sự kiện tùy biến để giải quyết vấn đề này. Để 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:
<button v-on:click="$emit('enlarge-text')"> |
Sau đó trong component <blog-post>
, 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:
<blog-post |
Gửi giá trị khi phát ra sự kiện
Đôi khi bạn cần gửi một giá trị cụ thể nào đó kèm với một sự kiện. Ví dụ, chúng ta có thể cho <blog-post>
quyền quyết định mức độ phóng đại của cỡ chũ. Trong những trường hợp này, ta có thể dùng tham số thứ hai của $emit
:
<button v-on:click="$emit('enlarge-text', 0.1)"> |
Sau đó, khi lắng nghe sự kiện này ở đối tượng cha, chúng ta có thể truy xuất đến giá trị của sự kiện được phát ra với $event
:
<blog-post |
Hoặc, nếu đó là một phương thức xử lí sự kiện:
<blog-post |
thì giá trị sẽ được truyền vào dưới dạng tham số đầu tiên của phương thức đó:
methods: { |
Sử dụng v-model
với component
Các sự kiện tùy biến có thể được sử dụng để tạo ra các <input>
tùy biến hoạt động với v-model
. Nhớ rằng:
<input v-model="searchText"> |
là hoàn toàn tương đồng với:
<input |
Khi sử dụng trên một component, v-model
là tương đồng với:
<custom-input |
Tuy nhiên để hoạt động được, phần tử <input>
trong component phải:
- Ràng buộc thuộc tính
value
với một propvalue
- Trong sự kiện
input
, phát ra sự kiệninput
tùy biến với giá trị mới
Một đoạn code hoàn chỉnh nhìn tương tự như thế này:
Vue.component('custom-input', { |
Giờ thì v-model
sẽ hoạt động ổn thỏa:
<custom-input v-model="searchText"></custom-input> |
Hiện giờ thì đó là tất cả những gì bạn cần biết về các sự kiện tùy biến của component, nhưng sau khi đọc xong trang này và hiểu thêm về component, bạn nên quay lại và đọc bản hướng dẫn đầy đủ về sự kiện tùy biến.
Phân phối nội dung với slot
Cũng như đối với các phần tử HTML, việc có thể truyền nội dung vào một component thường là rất hữu ích, ví dụ:
<alert-box> |
có thể render thành:
Việc này là rất đơn giản với phần tử tùy biến <slot>
của Vue:
Vue.component('alert-box', { |
Như bạn đã thấy trên đây, chúng ta chỉ cần thêm <slot>
vào nơi cần thể hiện nội dung, và thế là xong!
Hiện giờ thì đó là tất cả những gì bạn cần biết về slot, nhưng sau khi đọc xong trang này và hiểu thêm về component, bạn nên quay lại và đọc bản hướng dẫn đầy đủ về slot trong component.
Component động
Đô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:
Ví dụ trên hoạt động nhờ thuộc tính đặc biệt is
của một component trong Vue:
<!-- Component thay đổi khi currentTabComponent thay đổi --> |
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
Bạn có thể xem và thử thay đổi mã nguồn của ví dụ trên trên JSFiddle. Bạn cũng có thể dùng phiên bản này để xem ví dụ về cách ràng buộc vào object tùy chọn thay vì tên của component.
Hiện giờ thì đó là tất cả những gì bạn cần biết về component động, nhưng sau khi đọc xong trang này và hiểu thêm về component, bạn nên quay lại và đọc bản hướng dẫn đầy đủ về component động và không đồng bộ.
Lưu ý về việc parse DOM template
Bên trong các phần tử như <ul>
, <ol>
, <table>
và <select>
chúng ta chỉ có thể chứa một số phần tử nhất định (chẳng hạn <ul>
chỉ chấp nhận <li>
), trong khi đó các phần tử như <option>
lại chỉ có thể được đặt trong một số phần tử nhất định khác như <select>
, <optgroup>
, hay <datalist>
.
Điều này sẽ dẫn đến một số vấn đề khi dùng component với các phần tử có những hạn chế vừa nêu, ví dụ:
<table> |
Ở đây component <blog-post-row>
sẽ bị xem là một phần tử không hợp lệ bên trong <table>
và bị đẩy ra ngoài (hoisted out), dẫn đến lỗi khi render. Để giải quyết vấn đề này, ta có thể dùng thuộc tính đặc biệt is
:
<table> |
Cũng nên lưu ý rằng hạn chế này không tồn tại nếu bạn sử dụng template dạng chuỗi từ một trong các nguồn sau:
- Template dạng chuỗi, ví dụ
template: '...'
- Single file component
<script type="text/x-template">
Hiện giờ thì đó là tất cả những gì bạn cần biết về những lưu ý khi parse DOM template – và cũng là phần cuối của Cơ bản về component. Vẫn còn rất nhiều thứ khác để tìm hiểu, nhưng trước tiên bạn nên giải lao một chút và tạo ra cái gì đó vui vui với Vue. Sau khi đã hài lòng với những gì mình học được, bạn hãy quay lại và đọc các hướng dẫn đầy đủ và chuyên sâu hơn về component.