首先看下官方文档里Teleport的介绍,Teleport
也是一种组件,例如下面的代码,能够将<child-component name="John" />
组件传送到#endofbody
的标签里去渲染,同时,props
参数name="John"
可以正常传递。
<teleport to="#endofbody">
<child-component name="John" />
</teleport>
Teleport
组件,在代码中能保持原有布局层级、参数传递逻辑,但对应生成的Dom
,则传送到了to参数
指定的标签。
Teleport
主要用于“全屏模式的组件”,比如以下几种:
- 图片查看全屏显示
- 弹框(广告跳转框、提示框)
- 对话框(带有表单输入的、带有按钮的)
这里简单写一个Teleport
的组件示例
效果图
子组件mask.vue
<template>
<!-- Teleport 传送html到指定的标签body去渲染 -->
<teleport to="body">
<div>{{value}}</div>
<transition name="app-mask">
<div class="app-mask" v-show="show" @touchstart="close()">
<div class="app-mask-box" :class="['app-mask-' + type]">
<slot></slot>
</div>
</div>
</transition>
</teleport>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name:"mask",
props:{
show:{
type: Boolean,
default: false
},
clickHide:{ // 点击蒙版是否关闭
type: Boolean,
default:true
},
type:{ // center || bottom
type: String,
default: "center"
},
},
emits: ['update:show'], // 用emit声明子组件可以向其父组件触发的事件,官网强烈建议
setup:(props, context)=>{
const close = () => {
if(!props.clickHide){
return
}
// 触发v-model更新
context.emit('update:show', false)
}
return {
close
}
}
})
</script>
<style lang="less">
.app-mask{
background-color: fade(#000000, 60%);
position: fixed;
left: 0;
right: 0;
bottom: 0;
height: 100%;
z-index: 10000;
overflow: hidden;
opacity: 1;
transition: opacity 0.2s ease;
&-box{
position: absolute;
background: #fff;
margin: 20px;
}
// transition动画
&-enter, &-leave-active{
opacity: 0;
}
// center
&-center {
left: 0;
right: 0;
top: 50%;
transform: translateY(-50%);
transition: transform 0.2s ease;
}
&-enter &-center {
transform: scale(0.7);
}
&-leave-active &-center {
transform: scale(0.9);
}
// bottom
&-bottom {
left: 0;
right: 0;
bottom: 0;
transition: transform 0.2s linear;
}
&-enter &-bottom,
&-leave-active &-bottom {
transform: translate3d(0, 100%, 0);
}
}
</style>
父组件Demo.vue
<template>
<button @click="changeShow()">修改</button>
<!-- v-model:showMask 双向绑定 -->
<app-mask v-model:show="showDescPopup">
<h3>第一个弹框啦啦啦啦啦啦啦啦</h3>
</app-mask>
<app-mask v-model:show="showDescPopup2">
<h3>第二个弹框啦啦啦啦啦啦啦</h3>
</app-mask>
</template>
<script lang="ts">
import { defineComponent, ref, readonly } from 'vue'
import appMask from '../components/mask.vue'
export default defineComponent({
name: 'Demo',
components: {
appMask
},
setup(){
let showDescPopup = ref(false)
let showDescPopup2 = ref(false)
let show = ref(true)
const changeShow = () =>{
show.value = !show.value
showDescPopup.value = !showDescPopup.value
setTimeout(()=>{
showDescPopup2.value = !showDescPopup2.value
},2000)
}
return {
show, changeShow, showDescPopup, showDescPopup2
}
}
})
</script>