vue3-0 新特性 teleport 是啥,用起來真香
前言
在vue2.0
時代,我們經常會有這樣的需求,寫代碼邏輯的時候希望將組件寫在某個模板之下,因爲這樣我們很好的使用組件內部的狀態數據,控制組件的展示形態。但是從技術的角度上我們又希望將這段代碼移到DOM
中Vue app
之外的其他位置。
舉個簡單的例子,我們在使用modal
組件的時候,我們將它放在了我們的模板template
裏面,但是由於modal
組件希望位於頁面的最上方,這時候我們將modal
組件掛載在body
上面是最好控制的,我們能夠很好的通過zIndex
來控制modal
的位置,當他嵌套在templat
裏面的時候就不那麼容易了。
vue2.0 中的實現
vue2.0
中我在寫這個組件的時候是通過手動的形式來進行掛載的,我寫了一個 vue 指令來進行這個操作,幫助我將modal
組件掛載到body
上面去,專這樣也能夠很好的通過控制zIndex
來控制modal
的展示。
function insert(el) {
const parent = el.parentNode;
if (parent && parent !== document.body) {
parent.removeChild(el);
document.body.appendChild(el);
}
}
export default (typeof window !== 'undefined' ? {
inserted(el, { value }) {
if (value) {
insert(el);
}
},
componentUpdated(el, { value }) {
if (value) {
insert(el);
}
},
} : {});
上面的代碼其實就是簡單的將modal
從他原始掛載的父節點移除,然後掛載到body
上去,通過手動的形式來重新掛載,能夠很好的解決這種問題,當然上面只是簡單的邏輯,如果需要考慮卸載等其他邏輯代碼還得增加。
<template>
<div class="modal" v-to-body="show" v-if="show">
<div class="modal-mask" @click="close"></div>
<slot></slot>
</div>
</template>
<script>
import "./style.scss";
import toBody from "../directives/to-body";
export default {
props: {
show: Boolean,
},
directives: {
toBody,
},
methods: {
close() {
this.$emit("close");
},
},
};
</script>
說實話vue2.0
中的實現其實是沒啥問題的,只是不是很優雅,需要額外的代碼控制,所以vue3.0
中直接帶來了Teleport-任意傳送門
具體代碼參考 vue2.0-modal: https://codesandbox.io/s/vue20-modal-sc1rq
什麼是 Teleport
Teleport
能夠直接幫助我們將組件渲染後頁面中的任意地方,只要我們指定了渲染的目標對象。Teleport
使用起來非常簡單。
<template>
<teleport to="body" class="modal" v-if="show">
<div class="modal-mask" @click="close"></div>
<slot></slot>
</teleport>
</template>
<script>
import "./style.scss";
export default {
props: {
show: Boolean,
},
methods: {
close() {
this.$emit("close");
},
},
};
</script>
上面的代碼我們就能夠很簡單的實現之前 vue2.0 所實現的功能。
具體代碼參考 vue3.0-modal: https://codesandbox.io/s/vue3-modal-x2lud
注意點
與 Vue components 一起使用
在這種情況下,即使在不同的地方渲染child-component
,它仍將是parent-component
的子級,並將從中接收name prop
。
這也意味着來自父組件的注入按預期工作,並且子組件將嵌套在Vue Devtools
中的父組件之下,而不是放在實際內容移動到的位置。
const app = Vue.createApp({
template: `
<h1>Root instance</h1>
<parent-component />
`
})
app.component('parent-component', {
template: `
<h2>This is a parent component</h2>
<teleport to="#endofbody">
<child-component />
</teleport>
`
})
app.component('child-component', {
props: ['name'],
template: `
<div>Hello, {{ name }}</div>
`
})
在同一目標上使用多個 teleport
當我們將多個teleport
送到同一位置時會發生什麼?
<teleport to="#modals">
<div>A</div>
</teleport>
<teleport to="#modals">
<div>B</div>
</teleport>
<!-- result-->
<div id="modals">
<div>A</div>
<div>B</div>
</div>
我們可以看到對於這種情況,多個teleport
組件可以將其內容掛載到同一個目標元素。順序將是一個簡單的追加——稍後掛載將位於目標元素中較早的掛載之後。
總結
一句話來描述Teleport
就是一種將代碼組織邏輯依舊放在組件中,這樣我們能夠使用組件內部的數據狀態,控制組件展示的形式,但是最後渲染的地方可以是任意的,而不是侷限於組件內部
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/1UOvv3j4RuI9KzQ5mQwg8w