vue3 新组件之 Teleport,解决组件间 css 层级问题
最近在用 vue3 写一个小 ui 库,其中 dialog 组件的弹出框,涉及到了组件层级,也就是 z-index 的问题,下面我们来代码演示一下
首先是组件 html 部分的代码:
<template>
<template v-if="visible">
<!-- 遮罩层,z-index 为 10 -->
<div class="aha-dialog-overlay" @click="onClickOverlay"></div>
<!-- dialog 容器,z-index 为 11 -->
<div class="aha-dialog-wrapper">
<div class="aha-dialog">
<header>
<slot name="title"></slot><span @click="close" class="aha-dialog-close"></span>
</header>
<main>
<slot name="content"></slot>
</main>
<footer>
<Button level="main" @click="ok">OK</Button>
<Button @click="cancel">Cancel</Button>
</footer>
</div>
</div>
</template>
</template>
在父组件中引入 dialog 组件,效果如下:
目前来看是没什么问题的,那如果父组件中有一个层级高的标签呢?我在父组件写了两个容器,其中一个 z-index 为 1,里面包含了 dialog 组件,另一个 z-index 为 2,如下:
<template>
<div>Dialog 示例</div>
<h1>示例1</h1>
<!-- z-index 为 1 的父容器,里面包含了 dialog 组件-->
<div style="position: relative; z-index: 1">
<Button @click="toggle">toggle</Button>
<Dialog v-model:visible="x" :ok="f1" :cancel="f2">
<template v-slot:title>
<strong>加粗的标题</strong>
</template>
<template v-slot:content><strong>hi</strong></template>
</Dialog>
</div>
<!-- 层级高的标签,z-index 为 2 -->
<div style="
position: relative;
z-index: 2;
width: 300px;
height: 300px;
background: red;
"></div>
</template>
效果如下:
下面我们触发 dialog 显示事件:
可以看到 dialog 被挡在了红色方块的下面,因为元素在 html 中的层级是受父元素限制的,虽然我们给 dialog 设置了 z-index 为 11,但在父元素 z-index 为 1 的情况下,就算你给子元素设为 1000,他在页面中的层级也会比 z-index:2 要小。
vue3 新推出的组件 Teleport 就可以解决这个问题,让子组件不以父组件为层级参照,直接传送到 body 或者 其他元素下面
我们现在用 Teleport 标签把我们 dialog 组件需要提升层级的遮罩层 overlay 和弹出层 dialog 包裹起来:
再看一下效果:
ok,完美解决~