vue3中Teleport的用法以及使用場景小結(jié)
1. 基本概念
Teleport
是 Vue3 提供的一個內(nèi)置組件,它可以將組件的內(nèi)容傳送到 DOM 樹的任何位置,而不受組件層級的限制。這在處理模態(tài)框、通知、彈出菜單等需要突破組件層級限制的場景中特別有用。
1.1 基本語法
<template> <teleport to="body"> <!-- 這里的內(nèi)容會被傳送到 body 標(biāo)簽下 --> <div class="modal"> <!-- 模態(tài)框內(nèi)容 --> </div> </teleport> </template>
2. 常見使用場景
2.1 模態(tài)框
<!-- Modal.vue --> <template> <teleport to="body"> <div v-if="isOpen" class="modal-overlay"> <div class="modal"> <div class="modal-header"> <h3>{{ title }}</h3> <button @click="close">×</button> </div> <div class="modal-body"> <slot></slot> </div> <div class="modal-footer"> <slot name="footer"> <button @click="close">關(guān)閉</button> </slot> </div> </div> </div> </teleport> </template> <script setup> const props = defineProps({ isOpen: Boolean, title: String }) const emit = defineEmits(['update:isOpen']) const close = () => { emit('update:isOpen', false) } </script> <style scoped> .modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center; z-index: 1000; } .modal { background: white; padding: 20px; border-radius: 8px; min-width: 300px; } </style>
2.2 通知提示
<!-- Notification.vue --> <template> <teleport to="#notifications-container"> <div v-if="show" :class="['notification', type]" @click="close" > <div class="notification-content"> {{ message }} </div> </div> </teleport> </template> <script setup> import { ref, onMounted } from 'vue' const props = defineProps({ message: String, type: { type: String, default: 'info' }, duration: { type: Number, default: 3000 } }) const show = ref(true) const close = () => { show.value = false } onMounted(() => { if (props.duration > 0) { setTimeout(close, props.duration) } }) </script> <style scoped> .notification { position: fixed; top: 16px; right: 16px; padding: 12px 24px; border-radius: 4px; cursor: pointer; transition: all 0.3s; } .info { background: #e6f7ff; border: 1px solid #91d5ff; } .success { background: #f6ffed; border: 1px solid #b7eb8f; } .error { background: #fff2f0; border: 1px solid #ffccc7; } </style>
2.3 上下文菜單
<!-- ContextMenu.vue --> <template> <teleport to="body"> <div v-if="show" class="context-menu" :style="position" > <slot></slot> </div> </teleport> </template> <script setup> import { ref, computed } from 'vue' const props = defineProps({ show: Boolean, x: Number, y: Number }) const position = computed(() => ({ left: props.x + 'px', top: props.y + 'px' })) </script> <style scoped> .context-menu { position: fixed; background: white; border: 1px solid #eee; border-radius: 4px; padding: 8px 0; min-width: 160px; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); } </style>
3. 高級用法
3.1 動態(tài)目標(biāo)
<template> <teleport :to="target"> <div class="content"> 動態(tài)傳送的內(nèi)容 </div> </teleport> </template> <script setup> import { ref, onMounted } from 'vue' const target = ref('body') onMounted(() => { // 可以根據(jù)條件動態(tài)改變目標(biāo) if (window.innerWidth < 768) { target.value = '#mobile-container' } }) </script>
3.2 多個 Teleport 到同一目標(biāo)
<template> <teleport to="#notifications"> <div class="notification">通知 1</div> </teleport> <teleport to="#notifications"> <div class="notification">通知 2</div> </teleport> </template>
3.3 條件性傳送
<template> <teleport to="body" :disabled="isMobile"> <div class="modal"> <!-- 在移動端不會被傳送,保持原位置 --> </div> </teleport> </template> <script setup> import { ref, onMounted } from 'vue' const isMobile = ref(false) onMounted(() => { isMobile.value = window.innerWidth < 768 window.addEventListener('resize', () => { isMobile.value = window.innerWidth < 768 }) }) </script>
4. 實(shí)際應(yīng)用示例
4.1 全局加載指示器
<!-- LoadingIndicator.vue --> <template> <teleport to="body"> <div v-if="loading" class="loading-overlay"> <div class="loading-spinner"></div> <div class="loading-text">{{ message }}</div> </div> </teleport> </template> <script setup> defineProps({ loading: Boolean, message: { type: String, default: '加載中...' } }) </script> <style scoped> .loading-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.9); display: flex; flex-direction: column; justify-content: center; align-items: center; z-index: 9999; } </style>
4.2 圖片預(yù)覽器
<!-- ImageViewer.vue --> <template> <teleport to="body"> <div v-if="visible" class="image-viewer" @click="close" > <img :src="imageUrl" @click.stop > <div class="controls"> <button @click.stop="prev"><</button> <button @click.stop="next">></button> </div> </div> </teleport> </template> <script setup> const props = defineProps({ visible: Boolean, imageUrl: String, images: Array }) const emit = defineEmits(['update:visible']) const close = () => { emit('update:visible', false) } const prev = () => { // 實(shí)現(xiàn)上一張邏輯 } const next = () => { // 實(shí)現(xiàn)下一張邏輯 } </script>
5. 最佳實(shí)踐
5.1 目標(biāo)元素管理
<!-- index.html --> <!DOCTYPE html> <html> <head> <title>Vue App</title> </head> <body> <div id="app"></div> <!-- 為 Teleport 預(yù)留的容器 --> <div id="modals"></div> <div id="notifications"></div> <div id="tooltips"></div> </body> </html>
5.2 組件封裝
<!-- BaseModal.vue --> <template> <teleport to="#modals"> <transition name="modal"> <div v-if="modelValue" class="modal-container" @click.self="close" > <div class="modal-content"> <slot></slot> </div> </div> </transition> </teleport> </template> <script setup> defineProps({ modelValue: Boolean }) const emit = defineEmits(['update:modelValue']) const close = () => { emit('update:modelValue', false) } </script>
6. 注意事項
- 目標(biāo)元素存在性檢查
<template> <teleport to="#target" :disabled="!targetExists"> <div>內(nèi)容</div> </teleport> </template> <script setup> import { ref, onMounted } from 'vue' const targetExists = ref(false) onMounted(() => { targetExists.value = !!document.querySelector('#target') }) </script>
- SSR 兼容性
<template> <client-only> <teleport to="body"> <div>僅客戶端渲染的內(nèi)容</div> </teleport> </client-only> </template>
- 清理工作
<script setup> import { onUnmounted } from 'vue' onUnmounted(() => { // 確保清理所有傳送的內(nèi)容 const target = document.querySelector('#target') if (target) { target.innerHTML = '' } }) </script>
到此這篇關(guān)于vue3中Teleport的用法以及使用場景小結(jié)的文章就介紹到這了,更多相關(guān)Vue3 Teleport內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue.js實(shí)現(xiàn)含搜索的多種復(fù)選框(附源碼)
這篇文章主要給大家介紹了利用vue.js實(shí)現(xiàn)含搜索的多種復(fù)選框的相關(guān)資料,文中給出了簡單的介紹,但提供了完整的實(shí)例源碼供大家下載學(xué)習(xí),相信對大家具有一定的參考價值,需要的朋友們下面來一起看看吧。2017-03-03使用vue-print-nb打印el-table問題總結(jié)
這篇文章主要介紹了使用vue-print-nb打印el-table問題總結(jié),通過實(shí)例代碼介紹了vue-print-nb 打印功能,本文結(jié)合實(shí)例代碼講解的非常詳細(xì),感興趣的朋友一起看看吧2024-01-01ElementPlus 中el-select自定義指令實(shí)現(xiàn)觸底加載請求options數(shù)據(jù)的方法
觸底時,繼續(xù)向后端發(fā)請求獲取下一頁的數(shù)據(jù),請求回來的數(shù)據(jù)合并給options,這篇文章主要介紹了ElementPlus 中el-select自定義指令實(shí)現(xiàn)觸底加載請求options數(shù)據(jù)的操作方法,需要的朋友可以參考下2024-08-08vue2.0$nextTick監(jiān)聽數(shù)據(jù)渲染完成之后的回調(diào)函數(shù)方法
今天小編就為大家分享一篇vue2.0$nextTick監(jiān)聽數(shù)據(jù)渲染完成之后的回調(diào)函數(shù)方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-09-09vue開發(fā)chrome插件,實(shí)現(xiàn)獲取界面數(shù)據(jù)和保存到數(shù)據(jù)庫功能
這篇文章主要介紹了vue開發(fā)chrome插件,實(shí)現(xiàn)獲取界面數(shù)據(jù)和保存到數(shù)據(jù)庫功能的示例,幫助大家更好的理解和使用vue,感興趣的朋友可以了解下2020-12-12在vue中使用Echarts利用watch做動態(tài)數(shù)據(jù)渲染操作
這篇文章主要介紹了在vue中使用Echarts利用watch做動態(tài)數(shù)據(jù)渲染操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07解決Idea、WebStorm下使用Vue cli腳手架項目無法使用Webpack別名的問題
這篇文章主要介紹了解決Idea、WebStorm下使用Vue cli腳手架項目無法使用Webpack別名的問題,需要的朋友可以參考下2019-10-10vue子組件改變父組件傳遞的prop值通過sync實(shí)現(xiàn)數(shù)據(jù)雙向綁定(DEMO)
本文通過一個demo給大家介紹了vue子組件改變父組件傳遞的prop值通過sync實(shí)現(xiàn)數(shù)據(jù)雙向綁定,代碼簡單易懂,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2020-02-02