teleport 是 Vue 3 新增功能。teleport 就像是多啦A梦的「随意门」一样,只要设定了 teleport,就能够把 DOM 内容随意塞去画面上任个地方。例如当使用遮盖整个网页画面的 lightbox 或 modal 元件时,把它们塞到 body 让渲染就非常方便。
今天来点轻松的学习。teleport 的使用很简单,只需要把要移动的元素包起来即可:
<teleport to="body">
<p> 移动我到 body </p>
</teleport>
Teleport 有两个属性:
to
:移动的目的地。disabled
:
true
(预设):元素不会被移动。false
:元素会被移动到 to
指定的位置。使用 to
属性来指定目的地:
<teleport to="body"></teleport>
<teleport to=".box"></teleport>
<teleport to="#box"></teleport>
简单示范:
程序码:
<div class="box"></div>
<button @click="isDisabled = !isDisabled">移动</button>
<teleport to=".box" :disabled="isDisabled">
<p>移动我到 box</p>
</teleport>
data() {
return {
isDisabled: true,
};
}
.box {
background: pink;
height: 300px;
}
本身 p 是在 box 以外:
移动後:
disabled
,保留资料状态当动态切换 disabled
时,该元素的资料状态会得以保留,例如我在旁边加上点击次数,每次点击时都会累加 1:
最後,我们可以在多个元素上使用 teleport,并移动到同一目的地:
<div class="box"></div>
<teleport to=".box">
<p>文字 1</p>
</teleport>
<teleport to=".box">
<p>文字 2</p>
</teleport>
结果就会在 .box
里,依序出现「文字1」、「文字2」
网络上有很多例子都是示范 fullscreen modal。当我们要设定 fullscreen modal 时,通常会用到 position: fixed
来设置 modal。举例说:
<div class="box">
<Modal />
</div>
.box
是父层,如果 .box
设定了 transition
、perspective
或 filter
属性时,<Modal />
就无法以 viewport 作定位,只会以 .box
作定位。以致整个 modal 会跑版。
postion:fixed 的 MDN 解释:
以打开缩图浏览图片为例,每个Image
元件里都有一个 Lightbox
元件,用作放大显示这个图片。
App.vue
<template>
<div class="img-area">
<Image v-for="url in urls" :key="url" :url="url" />
</div>
</template>
data() {
return {
urls: [
"https://images.unsplash.com/photo-1632774240308-f54b5e4145ef?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1588&q=80",
"https://images.unsplash.com/photo-1632714657775-232ce19778a7?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1635&q=80",
"https://images.unsplash.com/photo-1632753043704-280dd515e81a?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1587&q=80",
"https://images.unsplash.com/photo-1627322307804-c87605cf3a89?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1665&q=80",
],
};
},
.img-area {
/* 父层加了 filter,以致 lightbox 跑版 */
filter: drop-shadow(16px 16px 20px grey);
}
Image.vue
<template>
<a href="#" @click="isOpen = true">
<img :src="url" alt="" />
</a>
<Lightbox :url="url" v-if="isOpen" @click="closeLightBox" />
</template>
Lightbox.vue
<template>
<div class="lightbox">
<img :src="url" alt="">
</div>
</template>
<style scoped>
.lightbox {
background: rgba(0, 0, 0, 0.3);
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: center;
align-items: center;
}
img {
width: 500px;
height: 500px;
object-fit: cover;
}
</style>
因为 App.vue .img-area
加了 filter 属性,因此,Lightbox 不再以 viewport 为锚点,变为以 .img-area
为锚点,以致跑版:
为了解决以上情况,可以使用 teleport 把 Lightbox 元件移动到 body 渲染:
Image.vue
<teleport to="body">
<Lightbox :url="url" v-if="isOpen" @click="closeLightBox" />
</teleport>
结果:
https://codesandbox.io/s/teleport-image-modal-wyrst?file=/src/components/Lightbox.vue:176-442
藉这些机会再练习一下 Vue,改良目前这个范例:
程序码的改动:
transform
属性作测试。https://codesandbox.io/s/teleport-image-gallery-k13u5
disabled
属性,决定是否要移动到 to
属性所指定的位置。并且会保留资料状态。Vue 3 - Teleport
Vue3 Composition API - Teleport 瞬移!
重新认识 Vue.js - 编译作用域与 Slot 插槽
<<: Day 28 - Build a Experimental Video Speed Controller UI
接下来我们会开始实作各个页面的逻辑,每个页面需要的资料不一样,适用的渲染模式也不一样,於是今天我们会...
接下来我会看看相关网页是如何设计的,这里参考了约 10 个国家的气象局官网,但囿於内容篇幅,仅简单列...
开始比较各种优化器 这边都先固定学习率0.01。 SGD+momentum(学习率设置0.001时,...
教材网址 https://coding104.blogspot.com/2021/06/java-o...
学习进度 JAVA常见错误(Error、Exception) 例外处理(throws、try cat...