【vue2】Vue Portal 和【vue3】Teleport

Vue Portal (用于vue2的插件)和 Vue3 Teleport (vue3内置特性)是两个可以在vue应用中更方便地控制组件渲染位置的工具

它们都可以将组件渲染到DOM结构的特定位置,而不是跟随父组件的渲染位置

Vue Portal

1、简单易用,Vue Portal是一个独立的插件,可以与vue2无缝集成,无需额外配置
2、可以在任何DOM元素中渲染组件,可以将组件渲染到应用之外的DOM元素中,例如body元素
3、可以通过使用不同的target属性,将组件渲染到不同的DOM元素中
4、对版本有限制,Vue Portal是为vue2设计的
5、需要额外的依赖,Vue Portal需要依赖第三方库portal-vue

Vue Portal使用:

1、安装

npm i `portal-vue`

2、main.js中引入

import PortalVue from 'portal-vue'
Vue.use(PortalVue)

3、PortalVue 包含两个组件,portal组件和portal-target组件,将portal组件中的内容转至portal-target组件所在的地方

1、A父页面中使用portal插件,to就是要去的DOM元素,destination${place}中的place是动态变量,假设值为1

<portal :to="`destination${place}`"
              >
              //作用域插槽,多个父组件需要传送内容,根据条件动态传送
                <div slot-scope="props" v-if="props.value == 'personId'">
                  <el-form-item
                    class="customFormItem"
                    :label="props.label ? `${props.label}:` : '申请人:'"
                    prop="personId"
                  >   
                        <el-input
     			   class="options"
    			    type="text"     
      			  v-model="form.personId"  
      />           
                  </el-form-item>
                </div>
              </portal>

2、B父页面中使用portal插件,to就是要去的DOM元素,destination${place}中的place是动态变量,假设值为2

<portal :to="`destination${place}`"
              >
              //作用域插槽,多个父组件需要传送内容,根据条件动态传送
                <div slot-scope="props" v-if="props.value == 'empName'">
                  <el-form-item
                    class="customFormItem"
                    :label="props.label ? `${props.label}:` : '领用人:'"
                    prop="empName"
                  >     
                        <el-input
        class="options"
        type="text"  
        v-model="form.empName"   
      />         
                  </el-form-item>
                </div>
              </portal>

3、子组件中使用portal-target,name就是传送地点, :name="destination${template.place}"中的place动态接收,假设A组件传过来的是1,即A组件portal包裹的内容将放在portal-target内, :name=“destination1”,假设B组件传过来的是2,即A组件portal包裹的内容将放在portal-target内, :name=“destination2”,很好理解吧

<template>
  <div class="formItem">
    <portal-target  //示例中A组件或B组件portal包裹的内容显示在这里
      v-if="template.isSend"
      :name="`destination${template.place}`"
      :slot-props="{ disabled, ...template }"
      multiple
    ></portal-target>
    <el-form-item
      v-else
      ref="formItem"
      :label="template.label + ':'"
      :prop="template.value"
      :title="template.label + ':'"
      :style="{
        width: template.editor === 'el-input-textarea' ? '80%' : '45.8%',
      }"
    >
      <el-input
        class="options"
        type="text"  
        v-model="template.value"   
      />         
        </el-form-item>
  </div>
</template>

vue 3 Teleport

1、vue3的内置特性,不需要额外的依赖
2、语法简洁,Vue3 Teleport 有一个简洁的语法来标记要将组件渲染到的位置
3、更好的性能,Vue3 Teleport的渲染机制得到了改进
4、仅适用于vue3项目
5、需要更多配置,在一些复杂场景下,可能需要更复杂的配置

vue 3 Teleport使用

<template>
  <teleport to="body">
    <MyTooltip v-if="isTooltipOpen" />
  </teleport>
  <button @click="toggleTooltip">Toggle Tooltip</button>
</template>

<script>
import { ref } from 'vue';

export default {
  components: {
    Teleport,
    MyTooltip,
  },
  setup() {
    const isTooltipOpen = ref(false);

    const toggleTooltip = () => {
      isTooltipOpen.value = !isTooltipOpen.value;
    };

    return {
      isTooltipOpen,
      toggleTooltip,
    };
  },
};
</script>

【vue3】Teleport 示例:
假设有一个三级嵌套的组件结构

App.vue

<template>
  <div class="app">
    <h3>我是APP组件</h3>
    <child />
  </div>
</template>

<script setup lang="ts">
</script>
<style >
.app {
  background-color: grey;
  padding: 10px;
}
</style>

child.vue

<template>
  <div class="child">
    <h3>我是child组件</h3>

    <myson />
  </div>
</template>

<script >
import { ref } from "vue";
export default {
  name: "child",
};
</script>
<style scoped >
.child {
  background: pink;
  padding: 10px;
}
</style>

myson.vue

<template>
  <div class="myson">
    我是myson 组件
    <Dialog />
  </div>
</template>

<script setup lang="ts">
</script>
<style scoped >
.myson {
  background: rgb(43, 198, 226);
  padding: 10px;
}
</style>

Dialog.vue

<template>
  <div>
    <button @click="isShow = true">点我显示</button>
    <div class="dialog" v-if="isShow">
      <div>内容</div>
      <div>内容</div>
      <div>内容</div>
      <div>内容</div>
      <div>内容</div>
      <div>内容</div>
      <div>内容</div>
      <div>内容</div>
      <div>内容</div>
      <button @click="isShow = false">点我隐藏</button>
    </div>
  </div>
</template>

<script>
import { ref } from "vue";
export default {
  name: "dialog",
  setup() {
    let isShow = ref(false);
    return {
      isShow,
    };
  },
};
</script>

<style >
.dialog {
  width: 300px;
  height: 300px;
  background-color: green;
}
</style>

在这里插入图片描述
在myson组件中再引入一个类似于弹窗的组件,每次切换显示与隐藏的时候,弹窗组件的内容会撑开所有组件的高度
在这里插入图片描述
弹窗组件包裹在三层组件内
在这里插入图片描述
如果想修改弹窗的位置,开启定位的话,定位是针对父元素,光是一层一层往上定位,如果中间还有别的定位,最后就会很容易把弹窗的位置定偏了
在这里插入图片描述
用Teleport组件可以把弹窗传送走,你想让它在谁下面就可以在谁的下面直接展示:

<template>
  <div>
    <button @click="isShow = true">点我显示</button>
    <teleport to="body">
      <div class="dialog" v-if="isShow">
        <div>内容</div>
        <div>内容</div>
        <div>内容</div>
        <div>内容</div>
        <div>内容</div>
        <div>内容</div>
        <div>内容</div>
        <div>内容</div>
        <div>内容</div>
        <button @click="isShow = false">点我隐藏</button>
      </div>
    </teleport>
  </div>
</template>

<script>
import { ref } from "vue";
export default {
  name: "dialog",
  setup() {
    let isShow = ref(false);
    return {
      isShow,
    };
  },
};
</script>

<style >
.dialog {
  width: 300px;
  height: 300px;
  background-color: green;
}
</style>

用了teleport传送到body之后,dialog与app就是平级的关系了
除了传送到body,还可以选择css选择器进行传送
在这里插入图片描述

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值