Teleport的妙用

202 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第23天,点击查看活动详情

前言

为什么我们需要使用Teleport?

中文文档:<Teleport> 是一个内置组件,它可以将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去。

Teleport是一种能将我们的模版移动到任意节点且能够保持自身状态不变(也就是不是通过删除和生成dom节点的操作),它是Vue3的内置组件。

现在我们来做这样一件事: 在页面上播放一个视频,当视频不在视窗内时,把视频移动到右下角继续播放视频,且保持播放的进度不变。

  • 需要用到video标签
  • 使用判断元素是否在视窗内的库,例如:Vueuse
  • 需要保持视频的状态不变

这个正是Teleport的拿手好戏。

实现需求

安装Vueuse:

yarn add @vueuse/core

需要使用到useIntersectionObserver这个函数,这个可以判断元素是否在视窗内。 注意:官方文档给了一个Tip:

挂载时,传送的 to 目标必须已经存在于 DOM 中。

代码:

<script setup>
import { ref, onMounted } from 'vue'
import { useIntersectionObserver } from '@vueuse/core'
var isTeleport = ref(true)
let show = ref(false)

const intersectionObserver = () => {
    useIntersectionObserver(document.getElementById('video'), ([{ isIntersecting }]) => {

        console.log(isIntersecting, isTeleport.value)
        isTeleport.value = isIntersecting
    })
}
onMounted(() => {
    intersectionObserver();
    setTimeout(() => {
        show.value = true;
    }, 1000)
})
</script>
<template>
    <div class="teleport">

    </div>
    <div class="video-container">
        <div id="video">
            <Teleport to=".teleport" :disabled="isTeleport" v-if="show">
                <video width="320" height="240" controls src="../assets/v02004740000besqmbakr6g9m0d8aho0.mp4" />
            </Teleport>
        </div>

    </div>

</template>

<style>
.video-container {
    width: 100vw;
    height: 1900px;
}

.teleport {
    position: fixed;
    bottom: 100px;
    right: 100px;
    width: 300px;
    height: 300px;

}
</style>

.teleport就是to目标元素,负责视频不在视窗内时的展示,在Teleport组件内包裹一个video标签,在Teleport上有个disabled,负责是否禁用Teleport,为true,组件的功能失效,会正常展示包裹的组件或者标签,为false,组件生效,会传送到to目标的DOM节点。在onMounted钩子函数内,执行intersectionObserver,负责视频是不是在视窗内。还有一个show,根据Tip的内容,用v-if去控制在目标节点渲染完成之后再去挂载Teleport。除此之外,还有一个.teleport节点,这个就是负责在小窗中展示视频,使用position:fixed将节点浮动在视窗固定的位置。

效果: