不管是Vue2 或Vue3 中都有內建元件的存在,如component 內建組件、transition 內建組件等等。內建元件就是官方給我們封裝的全域元件,我們直接拿來用就可以了。
在 Vue3 中新增了 Teleport 內建元件,先來看下官方文件是怎麼解釋的。
是內建元件,它可以將一個元件內部的一部分模板「傳送」到該元件的 DOM 結構外層的位置去。
通俗解釋:
teleport 是內建元件,我們都知道 HTML 是由層級關係的,Vue3 中的元件也是有層級關係的。
假如在父元件中引用了一個子元件,那麼渲染成頁面後面這個子元件 HTML 也是必然被父元件 HTML 包含的。
但是如果把子元件放置到了 teleport 元件中,那麼我們就可以指定該子元件渲染到父元件之外的其它 DOM 節點下,例如 body 或其它的 DOM 等等。這就有點類似與「傳送」了。
我們使用 Vue 的 UI 元件庫的時候,常常會用到模態框這個元件。如:使用 Element-plus 的模態框。
<template> <el-button @click="dialogVisible = true">打开弹窗</el-button> <el-dialog v-model="dialogVisible" append-to-body title="我是弹窗" width="30%"> </el-dialog> </template> <script> import { ref } from 'vue'; export default { setup(){ const dialogVisible = ref(false); return { dialogVisible } } } </script>
上段程式碼中在 App.vue 元件裡面引用了 Element-plus 的彈窗元件,並且新增了一個 append-to-body 屬性。
可以看到雖然彈窗元件是寫在App.vue 元件裡面的,但渲染出來的結果卻是彈窗元件屬於body 節點,這是因為利用了Element-plus 中彈窗的append-to-body 屬性,我們把該屬性去掉再看看什麼結果:
可以看到彈窗組件又乖乖的跑到了App.vue 元件下面。
為何要這麼做?
很簡單,假如有非常多的彈跳窗,那麼如何管理它們的z-index 呢,也就是同時彈跳窗戶時的層級關係,如果每個彈跳窗都在各自的父組件中,那麼我們是沒辦法控制的,所有有必要把它們都擰出來,放在同一個父元素下面,這樣就可以方便的設定層級關係了。
這和 teleport 元件有什麼關係嗎?有很大的關係,上面彈跳窗的 append-to-body 屬性效果是 Element 要為我們做的,如果我們想要自己實現這樣的效果,該怎麼辦呢?我們就可以使用內建元件 teleport 了。
<template> <div class="app"> App组件 <Teleport to="body"> <div>我是被 teleport 包裹的元素</div> </Teleport> </div> </template>
從上圖可以看出,Teleport 包裹的元素雖然是屬於app.vue 元件,但渲染後它卻被渲染在了body 這個dom 元素下面。
這都得歸功於Teleport 得傳送功能,它的用法很簡單,語法代碼如下:
其中to 就是「傳送」的目的地了,即需要把包裹的內容傳送到何處去。
<Teleport to="body"> </Teleport> to 允许接收值: 期望接收一个 CSS 选择器字符串或者一个真实的 DOM 节点。 提示: <Teleport> 挂载时,传送的 to 目标必须已经存在于 DOM 中。理想情况下,这应该是整个 Vue 应用 DOM 树外部的一个元素。 如果目标元素也是由 Vue 渲染的,你需要确保在挂载 <Teleport> 之前先挂载该元素。
< Teleport > 只改變了渲染的 DOM 結構,它不會影響元件間的邏輯關係。
也就是說,如果 < Teleport > 包含了一個元件,那麼這個元件總是和這個使用了 < teleport > 的元件保持邏輯上的父子關係。傳入的 props 和觸發的事件也會照常運作。
這也意味著來自父元件的注入也會按預期工作,子元件將在 Vue Devtools 中嵌套在父級元件下面,而不是放在實際內容移動到的地方。
// 父组件 <template> <div class="app"> <Teleport to="body"> <div>被 teleport 包裹的组件-- {{count}}</div> <ChildComponent v-model="count"/> </Teleport> </div> </template> <script> import { ref } from 'vue'; import ChildComponent from '@/components/childComponent'; export default { components:{ ChildComponent }, setup(){ const count = ref(100); return { count, } } } </script>
// 子组件 <template> 子组件:<input type="text" v-model.number="inputVal" @input="userInput"> </template> <script> import { ref, watch } from 'vue'; export default { props:{ modelValue:{ default:0, } }, setup(props,{emit}) { const inputVal = ref(null); const userInput = () => { emit('update:modelValue', inputVal.value) }; watch(props,(newVal,oldVal) => { inputVal.value = props.modelValue; },{immediate:true}) return { userInput, inputVal, } }, } </script>
在某些場景下可能需要視情況停用< Teleport >,我們可以透過對< Teleport > ; 動態地傳入一個disabled prop 來處理這兩種不同情況( disabled 屬性接收一個Boolean 值,true 代表不允許傳送,false 代表傳送)。
<template> <div class="app"> app组件 <Teleport to="body" :disabled="true"> <p>我是被 teleport 包裹的元素</p> <p>{{ message }}</p> </Teleport> </div> </template> <script> import { ref } from 'vue'; export default { setup(){ const message = ref('我是在 App 组件内部'); return { message, } } } </script>
多個< Teleport > 元件可以將其內容掛載在同一個目標元素上,而順序就是簡單的順次追加,後掛載的將排在目標元素下更後面的位置。
<!-- index.html --> <body> <div id="app"></div> <div id="customDom"></div> </body>
<template> app组件 <Teleport to="#customDom"> <p>我是被 teleport 包裹的一号元素</p> </Teleport> <Teleport to="#customDom"> <p>我是被 teleport 包裹的二号元素</p> </Teleport> </template>
以上是Vue3中內建元件Teleport怎麼使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!