跳转到内容

优化案例:视频列表只允许单个视频播放

刀刀

7/22/2025

0 字

0 分钟

场景复现

先来看看使用场景,有一个页面会有多个视频组件,现在要求其中一个视频播放时,其他视频都不能播放;上一个正在播放的视频也要停止播放。同时为了减轻包体积,不能使用 piniavuex 这种包管理工具。

项目效果图如下所示:

项目效果图

该项目是一个多人和做项目,组件被拆分为不同开发者负责,所以需要使用到设计模式。

组件代码如下所示:

vue
<script setup>
import HeaderVideo from './components/HeaderVideo.vue'
import VideoList from './components/VideoList.vue'
</script>

<template>
  <div>
    <HeaderVideo/>
    <div>其他内容</div>
    <div>其他内容</div>
    <VideoList/>
  </div>
</template>
vue
<script setup>
import { ref } from 'vue'
import VideoPlayer from './videoPlayer.vue'
</script>

<template>
  <div>
    <div>我是头部视频组件</div>
    <VideoPlayer/>
  </div>
</template>
vue
<script setup>
import { ref } from 'vue'
import VideoPlayer from './videoPlayer.vue'
</script>

<template>
  <div>
    <div>我是视频列表组件</div>
    <div>
      <VideoPlayer/>
      <VideoPlayer/>
      <VideoPlayer/>
      <VideoPlayer/>
    </div>
  </div>
</template>
vue
<script setup>
import { ref } from 'vue'
const videoDom = ref(null)
function play() {
  videoDom.value.play()
}
function pause() {
  videoDom.value.pause()
}
</script>

<template>
  <div>
    <video ref="videoDom" src="./test.mp4"></video>
    <button @click="() => play()">播放</button>
    <button @click="() => pause()">暂停</button>
  </div>
</template>

运行代码后,现在的效果是点击播放按钮后各自控制各自的视频组件,播放视频。

效果实现

这里用到观察者模式的思想,即一个视频播放时,通知上一个正在播放的视频组件暂停播放。这需要一个变量存储当前播放的视频组件,点击播放按钮时,调用播放函数,传参当前的视频组件 ref,然后通知上一个正在播放的视频组件暂停播放,再播放当前的视频组件,最后把当前的视频组件 ref 保存起来,用于下一次暂停。

js
export const videoObserver = {
  inPlay: null, // 当前正在播放的视频组件ref
  playVideo(videoDomRef) {
    // 如果有正在播放的视频组件,则暂停播放
    if (this.inPlay) {
      this.inPlay.pause()
    }
    videoDomRef.value.play()
    this.inPlay = videoDomRef // 保存当前播放的视频组件ref
  },
  pauseVideo(videoDomRef) {
    videoDomRef.value.pause()
  }
}
vue
<script setup>
import { ref } from 'vue'
import { videoObserver } from './observer.js'
const videoDom = ref(null)
function play() {
  videoDom.value.play() 
  videoObserver.playVideo(videoDom) 
}
function pause() {
  videoDom.value.pause() 
  videoObserver.pauseVideo(videoDom) 
}
</script>

<template>
  <div>
    <video ref="videoDom" src="./test.mp4"></video>
    <button @click="() => play()">播放</button>
    <button @click="() => pause()">暂停</button>
  </div>
</template>

现在开发者无需考虑其他开发者,只需要关注自己的组件即可,这样代码结构清晰,可维护性高。