Chào mừng đến với Cafedev! Trong bài viết này, chúng ta sẽ khám phá về tính năng Vuejs with Teleport. Teleport là một tính năng tích hợp sẵn trong Vue.js, cho phép teleport một phần của mẫu của một thành phần vào một nút DOM tồn tại ngoài cấu trúc DOM của chính thành phần đó. Hãy cùng tìm hiểu cách sử dụng Teleport để tạo ra các hiệu ứng và trải nghiệm người dùng tốt hơn trong ứng dụng Vue của bạn!


<Teleport> ref là một thành phần tích hợp sẵn cho phép chúng ta “teleport” một phần của mẫu của một thành phần vào một nút DOM tồn tại ngoài cấu trúc DOM của thành phần đó.

1. Cách Sử dụng Cơ Bản

Đôi khi chúng ta có thể gặp phải tình huống sau: một phần của mẫu của một thành phần thuộc về nó logic, nhưng từ góc nhìn trực quan, nó nên được hiển thị ở một nơi khác trong DOM, ngoài ứng dụng Vue.

Ví dụ phổ biến nhất về điều này là khi xây dựng một hộp thoại toàn màn hình. Lý tưởng, chúng ta muốn nút của hộp thoại và chính hộp thoại đều nằm trong cùng một thành phần, vì chúng đều liên quan đến trạng thái mở / đóng của hộp thoại. Nhưng điều đó có nghĩa là hộp thoại sẽ được kết xuất cùng với nút, sâu trong cấu trúc DOM của ứng dụng. Điều này có thể tạo ra một số vấn đề phức tạp khi định vị hộp thoại thông qua CSS.

Hãy xem xét cấu trúc HTML sau.

<div class="outer">
  <h3>Vue Teleport Example</h3>
  <div>
    <MyModal />
  </div>
</div>

Và đây là cách triển khai của <MyModal>:

Ví dụ kiểu Composition vs Options:

<script setup>
import { ref } from 'vue'

const open = ref(false)
</script>

  <button @click="open = true">Open Modal</button>

  <div v-if="open" class="modal">
    <p>Hello from the modal!</p>
    <button @click="open = false">Close</button>
  </div>

<style scoped>
.modal {
  position: fixed;
  z-index: 999;
  top: 20%;
  left: 50%;
  width: 300px;
  margin-left: -150px;
}
</style>
<script>
export default {
  data() {
    return {
      open: false
    }
  }
}
</script>

  <button @click="open = true">Open Modal</button>

  <div v-if="open" class="modal">
    <p>Hello from the modal!</p>
    <button @click="open = false">Close</button>
  </div>

<style scoped>
.modal {
  position: fixed;
  z-index: 999;
  top: 20%;
  left: 50%;
  width: 300px;
  margin-left: -150px;
}
</style>

Thành phần chứa một thẻ để kích hoạt việc mở modal, và một thẻ với một lớp .modal, sẽ chứa nội dung của modal và một nút để tự đóng lại.

Khi sử dụng thành phần này bên trong cấu trúc HTML ban đầu, có một số vấn đề tiềm ẩn:

  • Vị trí: cố định chỉ đặt phần tử liên quan đến cửa sổ xem khi không có phần tử tổ tiên nào có thuộc tính biến đổi, phối cảnh hoặc bộ lọc được thiết lập. Nếu, ví dụ, chúng ta có ý định thực hiện hiệu ứng biến đổi CSS trên phần tử tổ tiên <div class=”outer”>, điều này sẽ làm hỏng bố cục của modal!
  • Z-index của modal bị ràng buộc bởi các phần tử chứa nó. Nếu có một phần tử khác chồng lên với <div class=”outer”> và có một z-index cao hơn, nó sẽ che phủ modal của chúng ta.


<Teleport> cung cấp một cách làm sạch để làm việc xung quanh những vấn đề này, cho phép chúng ta thoát khỏi cấu trúc DOM lồng nhau. Hãy sửa đổi  <MyModal> để sử dụng <Teleport>:


<button @click="open = true">Open Modal</button>

<Teleport to="body">
  <div v-if="open" class="modal">
    <p>Hello from the modal!</p>
    <button @click="open = false">Close</button>
  </div>
</Teleport>

Mục tiêu to của <Teleport> mong đợi một chuỗi lựa chọn CSS hoặc một nút DOM thực sự. Ở đây, chúng ta đang essentially thông báo cho Vue “teleport mẫu fragment này đến thẻ body.

Bạn có thể kết hợp <Teleport> with <Transition> để tạo ra các hộp thoại có hiệu ứng – xem Ví dụ ở đây.
gợi ý Mục tiêu `to` của teleport phải tồn tại trong DOM khi thành phần `<Teleport>` được gắn kết. Lý tưởng, điều này nên là một phần tử ngoài toàn bộ ứng dụng Vue. Nếu muốn nhắm mục tiêu đến một phần tử khác được kết xuất bởi Vue, bạn cần đảm bảo rằng phần tử đó đã được gắn kết trước khi `<Teleport>` được gắn kết.

2.Sử dụng với Các Thành Phần

`<Teleport>` chỉ thay đổi cấu trúc DOM được kết xuất – nó không ảnh hưởng đến cấu trúc logic của các thành phần. Nói cách khác, nếu `<Teleport>` chứa một thành phần, thành phần đó sẽ vẫn là một con của thành phần cha chứa `<Teleport>`. Truyền props và phát ra sự kiện sẽ tiếp tục hoạt động theo cùng một cách.
Điều này cũng có nghĩa là các tiêm vào từ một thành phần cha hoạt động như mong đợi, và rằng thành phần con sẽ được lồng bên dưới thành phần cha trong Vue Devtools, thay vì được đặt ở nơi nội dung thực sự được di chuyển đến.

3. Vô Hiệu Hóa Teleport

Trong một số trường hợp, chúng ta có thể muốn vô hiệu hóa `<Teleport>` theo điều kiện. Ví dụ, chúng ta có thể muốn kết xuất một thành phần như một overlay cho desktop, nhưng inline trên di động. `<Teleport>` hỗ trợ prop `disabled` có thể được chuyển đổi động:

<Teleport :disabled="isMobile">
  ...
</Teleport>

Trạng thái `isMobile` có thể được cập nhật động bởi việc phát hiện thay đổi truy vấn phương tiện.

4.Nhiều Teleports trên Cùng Một Mục Tiêu

Một trường hợp sử dụng phổ biến sẽ là một thành phần `<Teleport>` có thể tái sử dụng, với khả năng có nhiều phiên bản hoạt động cùng một lúc. Đối với loại kịch bản này, nhiều thành phần `<Teleport>` có thể gắn kết nội dung của họ vào cùng một phần tử mục tiêu. Thứ tự sẽ là một việc gắn thêm đơn giản – các lần gắn sau sẽ được đặt sau các lần gắn trước trong phần tử mục tiêu.
Cho sử dụng sau:

<Teleport to="#modals">
  <div>A</div>
</Teleport>
<Teleport to="#modals">
  <div>B</div>
</Teleport>

Kết quả được kết xuất sẽ là:

<div id="modals">
  <div>A</div>
  <div>B</div>
</div>

Trên đây là những kiến thức hữu ích về Vuejs with Teleport mà chúng ta đã chia sẻ trên Cafedev. Hy vọng rằng thông tin này đã giúp bạn hiểu rõ hơn về tính năng này và cách áp dụng nó trong dự án của mình. Đừng quên tiếp tục theo dõi Cafedev để cập nhật những bài viết mới nhất về công nghệ và phát triển phần mềm. Cảm ơn bạn đã đồng hành cùng chúng tôi trên Cafedev!

Tham khảo thêm: MIỄN PHÍ 100% | Series tự học Vuejs từ cơ bản tới nâng cao

Các nguồn kiến thức MIỄN PHÍ VÔ GIÁ từ cafedev tại đây

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của CafeDev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!