11 【Teleport CSS功能】

本文详细介绍了Vue.js中的内置组件Teleport,包括基本用法、禁用、共享目标以及多Teleport的使用。Teleport解决了组件在DOM中定位的问题,不受父级样式影响。同时,文章还探讨了CSS功能,如CSS Modules、组件作用域CSS的深度选择器、插槽选择器和全局选择器的使用。提供了具体的代码示例和注意事项。
摘要由CSDN通过智能技术生成

21.内置组件 Teleport

什么是Teleport?——<Teleport> 是一个内置组件,它是一种能够将我们的模板渲染至指定DOM节点,不受父级style、v-show等属性影响,但data、prop数据依旧能够共用的技术;类似于 React 的 Portal。

主要解决的问题 因为Teleport节点挂载在其他指定的DOM节点下,完全不受父级style样式影响

  1. teleport 是内置组件,可以直接在模板中使用,无需注册。
  2. 可以被打包工具 tree-shake。所以它们只会在被使用的时候被引入。
  3. 需要直接主动访问(获取)它们的场景,也可以将它们显性导入。

21.1 基本用法

有时我们可能会遇到这样的场景:一个组件模板的一部分在逻辑上从属于该组件,但从整个应用视图的角度来看,它在 DOM 中应该被渲染在整个 Vue 应用外部的其他地方。

这类场景最常见的例子就是全屏的模态框。理想情况下,我们希望触发模态框的按钮和模态框本身是在同一个组件中,因为它们都与组件的开关状态有关。但这意味着该模态框将与按钮一起渲染在应用 DOM 结构里很深的地方。这会导致该模态框的 CSS 布局代码很难写。

父组件App.vue

<template>
  <div class="app">
    <h3>我是App组件</h3>
    <Child></Child>
  </div>
</template>

<script>
export default {
  name: 'App',
};
</script>

<script setup>
import Child from './components/Child.vue';
</script>

<style>
.app {
  background-color: gray;
  padding: 10px;
  /* position: relative; */
}
</style>

子组件Child.vue

<template>
  <div class="child">
    <h3>我是Child组件</h3>
    <button @click="isShow = true">打开遮罩层</button>
    <div class="mask" v-if="isShow">
      <div class="tip">
        这是一个提示
        <button @click="isShow = false">关闭</button>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'Child',
};
</script>

<script setup>
let isShow = $ref(false);
</script>

<style scoped>
.mask {
  position: absolute;
  z-index: 999;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  background-color: rgba(0, 0, 0, 0.3);
}

.tip {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  margin: auto;
}
</style>

现在来看没有问题

image-20220809195810727

可是如果父元素加一个定位:

  position: relative;

image-20220809195844153

遮罩层就会变成这样

以后嵌套组件变多了,遮罩组件的父级组件存在定位语句是很正常的。如果能把这个组件渲染到body标签的子标签就好了。这时就可以使用Teleport组件。

  • to - string :必传
    挂载的目标,只能是父级标签。兄弟、子级都会报错。
    挂载目标必须是有效的查询选择器或 HTMLElement

  • disabled - boolean :非必传

    • 是否禁用。true则挂载到目标节点下,false为当前位置。

    • 动态变化 disabled 值时,只是位置会变动,内容并不会销毁重新渲染!

<Teleport> 接收一个 to prop 来指定传送的目标。to 的值可以是一个 CSS 选择器字符串,也可以是一个 DOM 元素对象。这段代码的作用就是告诉 Vue “把以下模板片段传送到 body 标签下”。

父组件App.vue中使用组件的位置改成这样。

    <Teleport to="body">
      <Child></Child>
    </Teleport>

image-20220809200202370

可以发现这个组件确实被渲染到body标签下面了。

提示

<Teleport> 挂载时,传送的 to 目标必须已经存在于 DOM 中。理想情况下,这应该是整个 Vue 应用 DOM 树外部的一个元素。如果目标元素也是由 Vue 渲染的,你需要确保在挂载 <Teleport> 之前先挂载该元素。

以下teleport例子将会报错!

<div class="guazai" v-if="showData">teleport目标元素</div>
<div>
  <teleport to=".guazai">demo</teleport>
</div>
<script lang='ts'>
import { defineComponent } from 'vue'
export default defineComponent({
  data(){
    return {
      showData:false
    }
  },
  mounted() {
    setTimeout(() => {
      this.showData = true
    }, 1000*1);
  },
})
</script>

以下官方代码列举写法。但是前面说过 “ 挂载目标必须是有效的查询选择器或 HTMLElement ”

实际填h1 h2等原生标签、以及自定义的标签都是没问题的。以下应该是官方文档的一个纰漏。

<!-- 正确 -->
<teleport to="#some-id" />
<teleport to=".some-class" />
<teleport to="[data-teleport]" />

<!-- 错误 -->
<teleport to="h1" />
<teleport to="some-string" />

关于样式: teleport

teleport挂载的目标即使不在当前组件,scoped 内的样式在 teleport 中是生效的。

原因:scoped 生成的唯一属性会作用于 teleport 内的各元素

21.2 官方案例

试想下面这样的 HTML 结构:

<div class
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DSelegent

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值