- 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ũ
Transition cho enter/leave & danh sách
Để tiện đối chiếu giữa các class CSS mà Vue tạo ra trong một transition (chuyển tiếp) và trạng thái của các phần tử hoặc component, trong phần này chúng tôi giữ nguyên bản tiếng Anh các từ enter
(đi vào, nhập vào) và leave
(rời khỏi) khi cần.
Tổng quan
Vue cung cấp nhiều cách khác nhau để áp dụng các hiệu ứng transition khi các phần tử được thêm vào, thay đổi, hoặc gỡ bỏ khỏi DOM. Điều này bao gồm các công cụ để:
- tự động áp dụng các class CSS cho các transition và animation
- tích hợp các thư viện chuyển động CSS bên thứ ba, ví dụ như Animate.css
- sử dụng JavaScript để trực tiếp thay đổi DOM trong các hook transition
- tích hợp các thư viện chuyển động JavaScript bên thứ ba, ví dụ như Velocity.js
Trên trang này, chúng ta sẽ chỉ bàn về transition cho enter/leave và danh sách, nhưng bạn có thể xem phần tiếp theo về quản lí transition cho trạng thái (state transition).
Transition cho phần tử hoặc component đơn lẻ
Vue cung cấp một component transition
, cho phép bạn áp dụng các hiệu ứng transition enter/leave lên các phần tử hoặc component trong các ngữ cảnh sau:
- Render theo điều kiện (sử dụng
v-if
) - Hiển thị theo điều kiện (sử dụng
v-show
) - Component động
- Root node của component
Sau đây là một ví dụ:
<div id="demo"> |
new Vue({ |
.fade-enter-active, .fade-leave-active { |
Xin chào
Khi một phần tử chứa trong component transition
được thêm vào hoặc gỡ bỏ khỏi DOM, các bước sau đây sẽ diễn ra:
Vue sẽ tự phát hiện ra nếu phần tử đang nhắc đến có CSS
transition
hoặcanimation
và thêm/bớt các class CSS transition vào đúng thời điểm.Nếu component cung cấp hook JavaScript, các hook này sẽ được gọi vào đúng thời điểm.
Trong trường hợp không tìm thấy
transition
hoặcanimation
nào trong CSS và cũng không có hook JavaScript nào, việc thêm vào hoặc gỡ bỏ khỏi DOM sẽ được thực thi ngay trong frame tiếp theo (Lưu ý: đây là animation frame của trình duyệt, khác với khái niệmnextTick
của Vue).
Các class transition
Có tổng cộng 6 class được áp dụng cho enter/leave transition.
v-enter
: Trạng thái bắt đầu củaenter
. Được áp dụng trước khi phần tử được thêm vào DOM và gỡ bỏ đi một frame sau đó.v-enter-active
: Trạng thái active củaenter
. Được áp dụng trong suốt quá trình enter, từ ngay sau khi phần tử được thêm vào DOM cho đến khi transition/animation kết thúc. Class này có thể được dùng để định nghĩa duration, delay, và hàm easing cho transition enter.v-enter-to
: 2.1.8+. Trạng thái kết thúc củaenter
. Áp dụng một frame sau khi element được thêm vào DOM (cùng lúc với việcv-enter
được gỡ bỏ), gỡ bỏ đi khi transition/animation kết thúc.v-leave
: Trạng thái bắt đầu củaleave
. Được áp dụng ngay khi một leave transition được kích hoạt và gỡ bỏ đi một frame sau đó.v-leave-active
: Trạng thái active củaleave
. Được áp dụng trong suốt quá trình leave, từ khi transition được kích hoạt cho đến khi transition/animation kết thúc. Class này có thể được dùng để định nghĩa duration, delay, và hàm easing cho leave transition.v-leave-to
: 2.1.8+. Trạng thái kết thúc củaleave
. Áp dụng một frame sau khi leave transition được kích hoạt (cùng lúc với việcv-leave
được gỡ bỏ), gỡ bỏ đi khi transition/animation kết thúc.
Mỗi class trên đây sẽ có prefix (tiếp đầu ngữ) là tên của transition
. Ở đây prefix v-
là mặc định khi bạn dùng một thẻ <transition>
không có tên. Nếu chẳng hạn bạn dùng <transition name="my-transition">
thì class v-enter
sẽ trở thành my-transition-enter
.
v-enter-active
và v-leave-active
cho phép bạn dùng các hàm easing khác nhau cho các enter/leave transition, như bạn sẽ thấy trong phần tiếp theo đây.
CSS transition
CSS transition là một trong những transition thông dụng nhất. Ví dụ:
<div id="example-1"> |
new Vue({ |
/* |
Xin chào
CSS animation
CSS animation được áp dụng cùng một cách như CSS transition. Điểm khác nhau là v-enter
không được gỡ bỏ ngay lập tức sau khi phần tử được thêm vào DOM mà là khi sự kiện animationend
được phát ra.
Đây là một ví dụ (chúng ta sẽ bỏ đi các prefix CSS cho gọn):
<div id="example-2"> |
new Vue({ |
.bounce-enter-active { |
Cân đẩu vân
Class tùy biến cho transition
Bạn cũng có thể chỉ định các class tùy biến cho transition bằng cách cung cấp các thuộc tính sau đây:
enter-class
enter-active-class
enter-to-class
(2.1.8+)leave-class
leave-active-class
leave-to-class
(2.1.8+)
Các thuộc tính này sẽ override những tên class theo thông lệ của Vue. Điều này đặc biệt có ích khi bạn muốn kết hợp giữa hệ thống transition của Vue và một thư viện CSS animation có sẵn như Animate.css.
Đây là một ví dụ:
<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css"> |
new Vue({ |
Thú nhún
Sử dụng animation và transition cùng nhau
Vue cần phải đính kèm một sự kiện để có thể biết khi nào thì một chuyển động kết thúc. Sự kiện này có thể là transitionend
hoặc animationend
, tùy thuộc vào các rule CSS được áp dụng. Nếu bạn chỉ sử dụng animation hoặc transition, Vue có thể tự phát hiện kiểu chuyển động (animation hay transition).
Tuy nhiên, trong một số trường hợp có thể bạn muốn dùng cả transition và animation trên cùng một phần tử, ví dụ sử dụng Vue để kích hoạt một CSS animation, đồng thời áp dụng một hiệu ứng CSS transition khi hover. Trong những trường hợp này, bạn sẽ phải khai báo rõ kiểu chuyển động bạn muốn Vue xử lí bằng cách dùng một thuộc tính type
với giá trị là animation
hoặc transition
.
Chỉ định rõ thời lượng cho transition
2.2.0+
Trong đa số các trường hợp, Vue có thể tự biết được khi nào một transition kết thúc. Mặc định, Vue đợi cho sự kiện transitionend
hoặc animationend
của phần tử transition gốc được phát ra. Tuy nhiên, không phải lúc nào đây cũng là điều bạn muốn – ví dụ, chúng ta có thể có một chuỗi các transition nối tiếp nhau, trong đó một số phần tử bên trong có transition được trì hoãn (delay) hoặc kéo dài lâu hơn transition của phần tử transition gốc.
Trong những trường hợp như vậy, bạn có thể chỉ định một cách tường minh thời lượng (duration) của transition (với đơn vị là mili giây) dùng thuộc tính duration
trên component <transition>
:
<transition :duration="1000">...</transition> |
Bạn cũng có thể chỉ định hai giá trị tách biệt nhau cho thời lượng enter
và leave
:
<transition :duration="{ enter: 500, leave: 800 }">...</transition> |
Hook JavaScript
Bạn cũng có thể định nghĩa các hook JavaScript trong các thuộc tính của component <transition>
:
<transition |
// ... |
Những hook này có thể được sử dụng độc lập hoặc dùng chung với CSS transition/animation.
Khi sử dụng các transition JavaScript, hàm callback done
là bắt buộc đối với các hook enter
và leave
. Trong các trường hợp khác, các hook này sẽ được gọi một cách đồng bộ và transition sẽ kết thúc ngay lập tức.
Bạn cũng nên chỉ định rõ v-bind:css="false"
cho các transition JavaScript để Vue có thể bỏ qua phần dò tìm CSS. Việc này cũng ngăn không cho các rule trong CSS can thiệp vào transition.
Giờ chúng ta hãy xem một ví dụ. Đây là một transition JavaScript sử dụng Velocity.js:
<!-- |
new Vue({ |
Demo
Transition khi render lần đầu tiên
Nếu muốn áp dụng một transition ngay trong lần render đầu tiên của một node, bạn có thể dùng thuộc tính appear
:
<transition appear> |
Mặc định, các transition được chỉ định khi enter và leave sẽ được sử dụng. Nếu muốn, bạn cũng có thể dùng các class CSS tùy biến:
<transition |
và các hook JavaScript tùy biến:
<transition |
Transition giữa các phần tử web
Chúng ta sẽ bàn về transition giữa các component sau, nhưng bạn cũng có thể transition giữa các phần tử thô (raw element) sử dụng v-if
/v-else
. Một trong các transition giữa hai phần tử thông dụng nhất là giữa một phần tử chứa danh sách (ul
, ol
, table
…) và một thông điệp mô tả một danh sách rỗng:
<transition> |
Cách này hoạt động tốt, nhưng có một điểm cần lưu ý:
Khi kích hoạt giữa các phần tử có cùng tên thẻ, bạn phải cho Vue biết rằng đây là các phần tử khác nhau bằng cách cung cấp các giá trị key
duy nhất. Nếu không, trình biên dịch của Vue sẽ chỉ thay đổi nội dung của phần tử để hiệu quả hơn. Ngay cả khi về mặt kĩ thuật là không cần thiết, hãy luôn dùng key
cho các item trong một component <transition>
.
Ví dụ:
<transition> |
Trong những trường hợp này, bạn cũng có thể dùng thuộc tính key
cho việc chuyển tiếp giữa các trạng thái khác nhau trong cùng một phần tử. Thay vì dùng v-if
và v-else
, ví dụ trên có thể được viết lại như sau:
<transition> |
Thật ra chúng ta có thể chuyển tiếp giữa một số lượng bất kì các phần tử bằng cách dùng nhiều v-if
hoặc bind một phần tử đơn lẻ vào một thuộc tính động. Ví dụ:
<transition> |
Ví dụ trên cũng có thể được viết thành:
<transition> |
// ... |
Các chế độ transition
Chúng ta vẫn còn một vấn đề ở đây. Thử bấm vào nút bên dưới:
Khi việc chuyển tiếp giữa hai nút “bật” và “tắt” diễn ra, cả hai nút đều được render - một nút mờ dần trong khi nút kia rõ dần. Đây là hành vi mặc định của <transition>
- quá trình enter và leave xảy ra đồng thời.
Thỉnh thoảng đây là điều ta muốn, ví dụ khi chuyển tiếp giữa hai phần tử được sắp xếp chồng lên nhau:
Chúng ta cũng có thể sử dụng thêm translate
để tạo hiệu ứng giống như slide:
Tuy nhiên, không phải lúc nào chúng ta cũng muốn transition enter và leave xảy ra đồng thời. Vì thế, Vue cung cấp thêm một số chế độ transition thay thế:
in-out
: Transition đi vào (in) của phần tử mới xảy ra trước, và sau khi hoàn tất mới đến lượt transition đi ra (out) của phần tử hiện tại.out-in
: Transition đi ra (out) của phần tử hiện tại xảy ra trước, và sau khi hoàn tất mới đến lượt transition đi vào (in) của phần tử mới.
Bây giờ chúng ta thử cập nhật transition cho các nút bật/tắt với out-in
:
<transition name="fade" mode="out-in"> |
Vậy là chỉ cần thêm một thuộc tính, chúng ta đã sửa xong transition ban đầu mà không cần phải viết bất kì style CSS đặc biệt nào.
Chế độ in-out
không được dùng nhiều như out-in
, nhưng thỉnh thoảng cũng có thể hữu dụng khi dùng cho một hiệu ứng transition hơi khác một chút. Chúng ta hãy thử kết hợp in-out
với ví dụ slide-fade phía trên:
Không đến nỗi nào, đúng không?
Transition giữa các component
Transition giữa các component lại càng đơn giản hơn - chúng ta còn không cần dùng thuộc tính key
. Thay vào đó, chúng ta wrap một component động:
<transition name="component-fade" mode="out-in"> |
new Vue({ |
.component-fade-enter-active, .component-fade-leave-active { |
Transition cho danh sách
Đến lúc này, chúng ta đã bàn về transition cho:
- Các node đơn
- Nhiều node khác nhau nhưng chỉ có một node được render mỗi lúc
Vậy nếu chúng ta có một danh sách chứa các item mà ta muốn render đồng thời, ví dụ với v-for
, thì sao? Trong trường hợp này, ta sẽ dùng component <transition-group>
. Trước khi xem ví dụ, có một số điều quan trọng mà bạn cần biết về component này:
- Khác với
<transition>
,<transition-group>
render một phần tử thật sự, mặc định là<span>
. Bạn có thể thay đổi kiểu phần tử được render ra bằng thuộc tínhtag
. - Các phần tử bên trong
<transition-group>
bắt buộc phải có thuộc tínhkey
duy nhất
Transition enter/leave cho danh sách
Bây giờ chúng ta sẽ xem một ví dụ về transition cho enter/leave với cùng các class CSS mà ta đã dùng trên đây:
<div id="list-demo"> |
new Vue({ |
.list-item { |
Có một vấn đề với ví dụ này: Khi bạn thêm hoặc bớt một item, những item xung quanh nó ngay lập tức nhảy đến vị trí mới thay vì chuyển tiếp một cách mềm mại. Chúng ta sẽ giải quyết vấn đề này sau.
Transition dịch chuyển trong danh sách
Component <transition-group>
có một tính năng nữa. Không chỉ có thể animate enter và leave, nó còn có thể animate vị trí của các item. Khái niệm mới duy nhất bạn cần biết đến để sử dụng tính năng này là class v-move
, được thêm vào khi item thay đổi vị trí. Tương tự như các class khác, prefix của v-mode
chính là thuộc tính name
, và bạn có thể sử dụng một class khác với thuộc tính move-class
.
Class này có ích nhất là để chỉ định thời lượng và hàm easing cho transition, như có thể thấy sau đây:
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script> |
new Vue({ |
.flip-list-move { |
Nhìn thì có vẻ như là phép màu, nhưng thật ra ở bên trong Vue đang dùng một kĩ thuật animation gọi là FLIP để thay đổi vị trí của các item một cách mềm mại bằng transform
.
Chúng ta có thể kết hợp kĩ thuật này với các ví dụ phía trên để animate bất kì thay đổi nào xảy ra trong danh sách:
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script> |
new Vue({ |
.list-complete-item { |
Một điểm quan trọng cần lưu ý là các transition FLIP này không hoạt động đối với các phần tử có display: inline
. Để thay thế, bạn có thể dùng display: inline-block
hoặc đặt trong một flexbox.
FLIP animation cũng không bị giới hạn chỉ trong một trục. Item trong một grid (lưới) đa chiều cũng có thể được animate:
Cứ nằm khểnh bấm nút Xáo cho đến khi nào thắng thì thôi.
Chuẩn bị thêm thùng mì tôm càng tốt.
Transition tuần tự
Bằng cách giao tiếp với các transition JavaScript thông qua các thuộc tính dữ liệu, ta có thể khiến cho các transition trong một danh sách diễn ra một cách tuần tự:
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script> |
new Vue({ |
Transition tái sử dụng được
Transition có thể được tái sử dụng trong hệ thống component của Vue. Để tạo ra một transition sử dụng lại được, bạn chỉ cần đặt một component <transition>
hoặc <transition-group>
ở phần tử root, sau đó truyền bất cứ component con nào vào.
Đây là một ví dụ sử dụng một component template:
Vue.component('my-special-transition', { |
Và component chức năng (functional component) đặc biệt phù hợp cho nhiệm vụ này:
Vue.component('my-special-transition', { |
Transition động
Đúng, ngay cả transition trong Vue cũng hướng dữ liệu! Ví dụ cơ bản nhất của một transition động bind thuộc tính name
vào một property động.
<transition v-bind:name="transitionName"> |
Điều này có thể có ích khi bạn đã định nghĩa transition/animation CSS với quy chuẩn đặt tên cho class transition của Vue và muốn hoán chuyển giữa các transition/animation này.
Tuy nhiên, sự thật thì bất kì thuộc tính transition nào cũng có thể được bind động. Và không chỉ có thuộc tính. Vì thật ra chỉ là các phương thức, các hook cho sự kiện có thể truy xuất đến bất kì dữ liệu nào trong ngữ cảnh hiện tại. Điều này có nghĩa là tùy vào trạng thái của component, các transition JavaScript của bạn có thể có các hành vi rất khác nhau.
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script> |
new Vue({ |
Xin chào
Cuối cùng, cách tốt nhất để tạo transition động là thông qua các component nhận vào props
để thay đổi bản chất của transition đang dùng. Nói thì có vẻ sến, nhưng thực sự giới hạn duy nhất là trí tưởng tượng của bạn.