使用Vue3中的Teleport API实现B站视频播放效果

34 篇文章 5 订阅

需求描述:

咱们播放一个视频,然后当咱们向下滚动直至离开可视区域的时候,会在右下角出现一个小窗口继续咱们的视频播放。

效果: 

  

需求分析:

1. 初始化一个播放器

2. 大视频播放区域如果出现在视口外,小窗口出现

3. 大小视频切换的时候,保持视频状态不变

主要用到:

1. 一个成熟的播放器

2. vueuse中的 useIntersectionObserver API来监视某个dom元素是否离开了可视区域

3. Vue3中的 Teleport 内置组件 传送门 保持dom的前提下完成传送

接下来正题:

播放器

这里不是重点,选择一个自己喜欢的播放器就可以啦,就是随便播放个视频,我这里用的西瓜播放器,我将xgPlayer封装成了一个公共组件,在我上一篇 博客有写,感兴趣的话可以去踩踩,链接:vue使用西瓜播放器

useIntersectionObserver API

这个api可以帮我们很方便的监测到 某个dom元素 是否离开了 我们的可视区域

  安装

npm install @vueuse/core

 引入 

import { useIntersectionObserver } from '@vueuse/core'

 使用 

const { stop } = useIntersectionObserver(document.getElementById('bigBox'), ([{ isIntersecting }]) => {
  // isIntersecting  一个布尔值, true -> 代表在可视区域; false -> 表示不再可是区域
  isTeleport.value = isIntersecting
})

// setTimeout(() => {
//   stop()  // 不需要监听的时候 调用stop函数
// },10000)

Teleport 传送门 

官网:Teleport·传送门

 这个是Vue3提供的内置组件,可以直接使用,to属性传送到目标dom下,disabled控制什么时候传送

注意:  我们传送的时候to的那个目标dom,必须要挂载到Teleport之前才行

所以我们采用 v-if 来控制 Teleport 组件的挂载时机,保证Teleport挂载时,to 目标已经存在于dom之中

完整代码 

<template>
  <div class="TeleportVideo">

    <!-- 要播放的大视频窗口 -->
    <div id="bigBox">
      <Teleport to="#smallBox" :disabled="isTeleport" v-if="isShow">
        <XgPlayer :id="'xgPlayerId'" />
      </Teleport>
    </div>

    <!-- 要传送的小视频窗口 -->
    <div id="smallBox"></div>

    <!-- 模拟滚动 -->
    <div style="height: 2000px;"></div>
  </div>
</template>
<script setup>
import { onMounted, ref } from 'vue'
import XgPlayer from '@/components/xgPlayer/xgPlayer.vue'
import { useIntersectionObserver } from '@vueuse/core'


let isTeleport = ref(true)  //  控制什么时候传送
let isShow = ref(false)  // 控制 Teleport内置组件的挂载时机(要延迟一下)

onMounted(() => {
  intersectionObserver()
  //  为了确保传送的目标dom挂载时机在Teleport组件之间  所以这里延迟挂载Teleport内置组件
  setTimeout(() => {  // 这里不用setTimeOut也是可以的,咱们就是想让Teleport内置组件在最后的时候挂载,onMounted执行的时候,dom元素已经挂载完成了
    isShow.value = true
  })
})


// 监听 指定的dom元素是否在 可视区域内
const intersectionObserver = () => {
  const { stop } = useIntersectionObserver(document.getElementById('bigBox'), ([{ isIntersecting }]) => {
    // isIntersecting  一个布尔值, true -> 代表在可视区域; false -> 表示不再可是区域
    isTeleport.value = isIntersecting
  })

  // setTimeout(() => {
  //   stop()  // 不需要监听的时候 调用stop
  // },10000)
}
</script>
<style scoped>
.TeleportVideo {
  width: 100%;
  height: 100%;
  overflow: auto;
}

#bigBox {
  width: 640px;
  height: 360px;
  /* border: 10px solid red; */
  z-index: 99;
}
#smallBox {
  position: fixed;
  bottom: 20px;
  right: 60px;
  width: 320px;
  height: 180px;
  /* border: 1px solid red; */
}
</style>
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

会说法语的猪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值