vue3.0新特性teleport是啥,用起來(lái)真香
前言
在vue2.0時(shí)代,我們經(jīng)常會(huì)有這樣的需求,寫(xiě)代碼邏輯的時(shí)候希望將組件寫(xiě)在某個(gè)模板之下,因?yàn)檫@樣我們很好的使用組件內(nèi)部的狀態(tài)數(shù)據(jù),控制組件的展示形態(tài)。但是從技術(shù)的角度上我們又希望將這段代碼移到DOM中Vue app之外的其他位置。
舉個(gè)簡(jiǎn)單的例子,我們?cè)谑褂?code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">modal組件的時(shí)候,我們將它放在了我們的模板template里面,但是由于modal組件希望位于頁(yè)面的最上方,這時(shí)候我們將modal組件掛載在body上面是最好控制的,我們能夠很好的通過(guò)zIndex來(lái)控制modal的位置,當(dāng)他嵌套在templat里面的時(shí)候就不那么容易了。
vue2.0中的實(shí)現(xiàn)
vue2.0中我在寫(xiě)這個(gè)組件的時(shí)候是通過(guò)手動(dòng)的形式來(lái)進(jìn)行掛載的,我寫(xiě)了一個(gè)vue指令來(lái)進(jìn)行這個(gè)操作,幫助我將modal組件掛載到body上面去,專(zhuān)這樣也能夠很好的通過(guò)控制zIndex來(lái)控制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);
}
},
} : {});
上面的代碼其實(shí)就是簡(jiǎn)單的將modal從他原始掛載的父節(jié)點(diǎn)移除,然后掛載到body上去,通過(guò)手動(dòng)的形式來(lái)重新掛載,能夠很好的解決這種問(wèn)題,當(dāng)然上面只是簡(jiǎn)單的邏輯,如果需要考慮卸載等其他邏輯代碼還得增加。
<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>
說(shuō)實(shí)話vue2.0中的實(shí)現(xiàn)其實(shí)是沒(méi)啥問(wèn)題的,只是不是很優(yōu)雅,需要額外的代碼控制,所以vue3.0中直接帶來(lái)了Teleport-任意傳送門(mén)
具體代碼參考vue2.0-modal: https://codesandbox.io/s/vue20-modal-sc1rq
什么是Teleport
Teleport能夠直接幫助我們將組件渲染后頁(yè)面中的任意地方,只要我們指定了渲染的目標(biāo)對(duì)象。Teleport使用起來(lái)非常簡(jiǎn)單。
<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>
上面的代碼我們就能夠很簡(jiǎn)單的實(shí)現(xiàn)之前vue2.0所實(shí)現(xiàn)的功能。
具體代碼參考vue3.0-modal: https://codesandbox.io/s/vue3-modal-x2lud
注意點(diǎn)
與 Vue components 一起使用
在這種情況下,即使在不同的地方渲染child-component,它仍將是parent-component的子級(jí),并將從中接收name prop。
這也意味著來(lái)自父組件的注入按預(yù)期工作,并且子組件將嵌套在Vue Devtools中的父組件之下,而不是放在實(shí)際內(nèi)容移動(dòng)到的位置。
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 name="John" />
</teleport>
`
})
app.component('child-component', {
props: ['name'],
template: `
<div>Hello, {{ name }}</div>
`
})
在同一目標(biāo)上使用多個(gè)teleport
當(dāng)我們將多個(gè)teleport送到同一位置時(shí)會(huì)發(fā)生什么?
<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>
我們可以看到對(duì)于這種情況,多個(gè)teleport組件可以將其內(nèi)容掛載到同一個(gè)目標(biāo)元素。順序?qū)⑹且粋€(gè)簡(jiǎn)單的追加——稍后掛載將位于目標(biāo)元素中較早的掛載之后。
總結(jié)
一句話來(lái)描述Teleport就是一種將代碼組織邏輯依舊放在組件中,這樣我們能夠使用組件內(nèi)部的數(shù)據(jù)狀態(tài),控制組件展示的形式,但是最后渲染的地方可以是任意的,而不是局限于組件內(nèi)部
- END -
點(diǎn)贊 + 在看 + 分享,一鍵三連,幸福滿(mǎn)滿(mǎn)!
