您的当前位置:首页正文

vue实现滚动到视频离开可视区后出现小窗(类似b站小窗)

2024-11-27 来源:个人技术集锦


前言

最近在做的仿网易云播放器项目中,视频界面有个需求:当滚动条滚动到主视频界面离开可视窗口时,出现小窗继续播放。
HTML5 video 标签的画中画功能只能实现用户点击才会出现,滚动事件不能触发画中画
所以只能自己手写视频小窗播放


一、实现原理

二、实现过程

1.创建出所需的元素和数据

html 代码如下(css样式就不贴了):

<!-- 主视频 -->
<div class="video">
      <video
        :src="url"   data 中的数据
        controls
        ref="video"
        class="player"
        :poster="detail.cover || detail.coverUrl"
        @play="isVideoPlay = true"   记录主视频的播放状态,这里也可以不用记录,后面
        @pause="isVideoPlay = false"     通过videoElement.paused 判断
      ></video>
</div>
<!-- 小窗视频 -->
<div class="miniVideo" v-show="showMiniVideo">
	 <video
	   :src="url"
	   ref="miniVideo"
	   class="player"
	   :poster="detail.cover || detail.coverUrl"
	 ></video>
	 <!-- 遮罩,参考b站小窗 -->
	 <div class="mask">
	   <i
	     class="iconfont"
	     :class="{
	       'icon-icon_play': !isMiniVideoPlay,  通过miniVideo的播放状态显示不同的按钮,如:播放,暂停
	       'icon-zanting2': isMiniVideoPlay,
	     }"
	     @click="miniVideoChangePlay(!isMiniVideoPlay)"  改变播放状态函数
	   ></i>
	 </div>
</div>

2.监听 mainVideo

利用 Intersection Observer API 实现


vue代码如下(我写在 mounted 生命周期函数中):

 // 滚动 出现小窗播放
 let video = this.$refs.video;
 let miniVideo = this.$refs.miniVideo;
 let videoOnce = false; // 是否执行过一次
 let miniVideoOnce = false;
 // 网页支持播放视频时
 video.oncanplay = () => {
   let observer = new IntersectionObserver((entries) => {
     // 视频窗口出现在可视窗口时
     if (entries[0].isIntersecting) {
       if (!videoOnce) {
         // 隐藏小窗
         this.showMiniVideo = false;
         // 同步播放时间
         video.currentTime = miniVideo.currentTime;
         // 同步播放状态
         this.isVideoPlay = this.isMiniVideoPlay;
         this.isVideoPlay ? video.play() : video.pause();
         // 暂停小窗
         this.isMiniVideoPlay = false;
         miniVideo.pause();
         // 因为会出现执行两次的情况,所有用这个变量来判断是否执行过一次
         // 执行过一次后要在执行else里的动作才会解除执行过一次的状态
         // 避免出现视频已暂停还执行暂停而报错,或其他问题
         videoOnce = true;
         miniVideoOnce = false;
       }
     } else {
       if (!miniVideoOnce) {
         this.showMiniVideo = true;
         miniVideo.currentTime = video.currentTime;
         this.isMiniVideoPlay = this.isVideoPlay;
         this.isVideoPlay = false;
         this.isMiniVideoPlay ? miniVideo.play() : miniVideo.pause();
         video.pause();
         miniVideoOnce = true;
         videoOnce = false;
       }
     }
   });
   observer.observe(video);
 };

总结

有个缺点就是 miniVideo 隐藏或显示时,会有一瞬间的卡顿。

显示全文