Teleport

284 阅读2分钟

前言

三月份了,金三银四了吗,答案是没有,公司的项目还是那样的让人乏味,走也走不掉,学也学不起来,那就看看视频吧,今天看到一个视频是讲vue3中的Teleport,今天就来简单的了解下。

Teleport介绍

Teleport按照英文字面的意思是:远距离传送,他的作用是将一个组件传送到指定的位置。

网上有很多的例子来讲这个Teleport,最明显的例子就是弹框,这里简单的介绍下。

用到的文件有三个,app.vue HelloWorld.vue test1.vue

image.png

app.vue

<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
  components: {HelloWorld},
}

</script>

<template>
  <div>疯狂星期四</div>
  <HelloWorld msg="Vite + Vue"/>
</template>

HellWorld.vue

<script>
import { ref,defineComponent } from 'vue'
import test1 from './test1.vue'

export default defineComponent({
  components: {test1},
  setup(props, content) {
    const show_test1 = ref(false);
    const getparam = (val) => {
      show_test1.value = val
    }
    return {show_test1, getparam}
  }
})
</script>

<template>
  <div>
    世界之大,无奇不有
    <button @click="show_test1 = !show_test1">显示或隐藏组件test1</button>
    <test1 v-show="show_test1" @Tohidden_test1="getparam"></test1>
  </div>
</template>

<style scoped>
.read-the-docs {
  color: #888;
}
</style>

test1.vue

<template>
<div id="test1">
  这是测试组件test1
  <br/>
  <button @click="hidden_test1">隐藏组件1</button>
</div>
</template>

<script>
import { defineComponent } from "vue";
export default defineComponent({
setup(props,content){

  const  hidden_test1 = ()=>{
    content.emit('Tohidden_test1',false)
  }
  return{ hidden_test1 }
}

})

</script>

<style scoped>
#test1{
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: #747bff;
}
</style>

默认显示页面如下:

image.png

当点击"显示或隐藏组件test1"时,页面如下:

image.png

点击”隐藏组件1"又会和默认显示的页面一样。这样的一个弹框看似没有什么太大的毛病,那就一定是有问题的

加入我们给父组件HellWorld添加一层蒙版,让他变得模糊时,页面是这样的。

HellWorld.vue:

<script>
import { ref,defineComponent } from 'vue'
import test1 from './test1.vue'

export default defineComponent({
  components: {test1},
  setup(props, content) {
    const show_test1 = ref(false);
    const getparam = (val) => {
      show_test1.value = val
    }
    return {show_test1, getparam}
  }
})
</script>

<template>
  <div id="add_opacity">
    世界之大,无奇不有
    <button @click="show_test1 = !show_test1">显示或隐藏组件test1</button>
    <test1 v-show="show_test1" @Tohidden_test1="getparam"></test1>
  </div>
</template>

<style scoped>
.read-the-docs {
  color: #888;
}
#add_opacity{
  opacity: 0.3;
}
</style>

当点击"显示或隐藏组件test1"时,页面如下:

image.png

很显然的这层蒙版影响到了子组件test1的显示。

这个时候就到了Teleport大显身手的时候了,我们可以利用它来与app.vue页面保持在一个等级。

首先是index.html中添加一个id为test_Teleport的div

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + Vue</title>
  </head>
  <body>
    <div id="app"></div>
    <div id="test_Teleport"></div>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>

修改test1中的代码如下:

<template>
  <Teleport to="#test_Teleport">
    <div id="test1">
      这是测试组件test1
      <br/>
      <button @click="hidden_test1">隐藏组件1</button>
    </div>
  </Teleport>
</template>

<script>
import { defineComponent } from "vue";
export default defineComponent({
setup(props,content){

  const  hidden_test1 = ()=>{
    content.emit('Tohidden_test1',false)
  }
  return{ hidden_test1 }
}

})

</script>

<style scoped>
#test1{
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: #747bff;
}
</style>

这样我们就能保证当前的弹框是在最顶层的,与#app是在同一级的。

效果如下:

image.png

动态传送位置,状态不发生改变

HelloWorld.vue

<script>
import { ref,defineComponent } from 'vue'
import test1  from "./test1.vue";
export default defineComponent({
  components: {test1},
  setup(props, content) {
    const show_test1 = ref(false);
    const direction = ref('#one');
    const changeDirection = () => {
      show_test1.value = true
      if (direction.value == '#one') {
        direction.value = '#two';
      } else {
        direction.value = '#one';
      }
    }
    return {show_test1, direction, changeDirection}
  }
})
</script>

<template>
  <div>世界之大,无奇不有</div>
  <button @click="changeDirection">改变传送放向</button>
  <test1 :param="direction" v-if="show_test1"></test1>
  <div id="one">1</div>
  <div id="two">2</div>
</template>

<style scoped>
.read-the-docs {
  color: #888;
}
#one{
  height: 200px;
  width: 400px;
  border: 1px solid black;
}
#two{
  height: 200px;
  width: 400px;
  border: 1px solid lightgray;
}
</style>

test1.vue

<template>
  <Teleport :to="params">
    <div id="test">
      <div>⏲计时开始:{{ number }}</div>
    </div>
  </Teleport>
</template>

<script>
import {defineComponent, ref, onMounted, defineProps,watch  } from "vue";

export default defineComponent({
  props: {
    param: {
      type: String,
      default: '#one'
    }
  },
  setup(props, content) {
    const number = ref(0);
    const params = ref(props.param);
    watch(() => props.param, () => {
      params.value = props.param
    })
    onMounted(() => {
      setInterval(() => {
        number.value++;
      }, 1000)
    })
    return {number, params}
  }
})

</script>

<style scoped>
#test {
  width: 300px;
  height: 300px;
}
</style>

页面效果如下:

image.png

当点击:改变传送方向时,计时器不会从零开始,依然保持原有的状态。

Teleport属性disabled,当值为tue时不发生传送,当值为false时发生传送