如何快速开发一个自定义的视频播放器(6)——组件封装

443 阅读4分钟

组件封装

无论是日常生活中,还是工作coding中,我们很早就学会了复制黏贴,人人都是CV工程师。任何东西只要有了模板,那么很快就会被复制复制再复制,复制往往是简单的,而组件封装就是为了方便复制而创造的。正常来说,如果我们没有做组件化,那么我们想在其他地方使用我们刚开发的视频播放器,就需要去copy一份html,然后再copy一份css,最后再copy一份js,然后再调试来调试去,改方法呀,改样式呀balabala。一套搞下来,基本半天就过去了。那么如果我们使用了组件化,这半天的时间完全可以省下。本文基于vue2大致聊一下组件封装的简单方法。

抽离

通过观察我们的代码可以看到,我们的方法、样式和模板基本都十分内聚。所以我们直接新建一个videoComponent.vue把我们的video相关的代码抽离出来如下:

// ./videoComponent.vue
<style lang="less">
.video-wrapper {
 // ... css代码
}
</style>
<template>
  <div class="video-wrapper">
    <!-- html代码 -->
  </div>
</template>
<script>
// js代码
export default {
   // ...
}
</script>

抽离之后我们原来的页面就变为了:

<style lang="less">
.video {
  position: relative;
  width: 100%;
  height: 100%;
  min-height: 100vh;
  font-size: 0;
  box-sizing: border-box;
  * {
    box-sizing: border-box;
  }
  img {
    pointer-events: none;
  }
}
</style>
<template>
  <section class="video">
    <!--抽离-->
  </section>
</template>
<script>
export default {
 // ...
}
</script>
定义

考虑到我们需要一个视频组件,只需要几个基本的功能,可以播放不同的src,可以设置不同的poster,可以在开始播放时、视频播放时和视频暂停时做点什么,那么我们的组件即可定义为:

 <video-component
      :src="videoSrc"
      :poster="poster"
      @playing="OnPlay"
      @play="Start"
      @pause="Pause"
    ></video-component>

相应的我们最初的模板就变成了这样:

<template>
  <section class="video">
    <video-component
      :src="videoSrc"
      :poster="poster"
      @playing="OnPlay"
      @play="Start"
      @pause="Pause"
    ></video-component>
  </section>
</template>
<script>
import videoComponent from './videoComponent.vue'
export default {
  name: 'videoTest',
  data() {
    return {
      videoSrc:
        'https://cdn.cn/dubbing/2018-08-01/1533112489556mdamt929nwz.mp4',
      poster:
        'https://cdn.cn/2024-03-19/171083686254726059014.jpg-thumb'
    }
  },
  components: {
    videoComponent
  },
  methods: {
    OnPlay(ctime) {
      console.log('currentTime', ctime)
    },
    Start() {
      console.log('video is palyed')
    },
    Pause() {
      console.log('video is paused')
    }
  }
}
</script>

也就是说我们的组件只要实现这些功能即可

实现

可以看到我们只需要添加两个props和三个方法即可

  1. 定义两个属性
  // 
  props: {
    src: {
      type: String
    },
    poster: {
      type: String
    }
  },

同时同步到模板上

  1. 定义三个方法,方法由于是通过$emit触发,因此我个人的习惯是把所有需要暴露的方法名定义为常量,方便阅读和维护
// 定义组件回调方法
// 播放获取currentTime
const PLAYING = 'playing'
// 暂停
const PAUSE = 'pause'
// 播放
const PLAY = 'play'

video.ontimeupdate = () => {
    //... other code
    this.$emit(PLAYING, video.currentTime)
}

video.onpause = () => {
    //... other code
    this.$emit(PAUSE)
}

video.onplay = () => {
    //... other code
    this.$emit(PLAY)
}
动态切换

以上我们已经可以直接运行我们的demo会发现基本和原来的demo没有任何区别,而且我们能够在任何页面嵌入该组件。但是考虑一种场景,一开始我们是拿不到视频资源链接或者我们有一堆视频列表,需要随时切换不同的视频资源,那么我们的组件能否支持呢。显然现在是不能支持的,所以需要去监听我们的src的变化,当src改变时再初始化我们的视频信息,这里我们使用watch:

 watch: {
    src(a, b) {
      console.log(a, b)
      this.video.target.pause()
      this.showPannel = false
      this.showStartPlay = true

      this.video = {
        target: null,
        currentTime: 0,
        currentTimeString: '00:00',
        duration: 0,
        durationString: '00:00',
        status: 'pause',
        progress: 0,
        starting: false,
        showTime: 2000,
        showTimer: null,
        offsetCurrentTime: 0,
        canplay: false
      }
      this.moveinfo = {
        progressWidth: 0,
        minX: 0,
        maxX: 0,
        currentX: 0
      }
      this.LoadVideo(this.$refs.video, () => {
        this.$nextTick(() => {
          this.PlayVideo()
        })
      })
    }
  }

这里我们为LoadVideo添加了渲染回调,当我们的视频信息都渲染好之后再开始播放

 LoadVideo(video, callback) {
  // other code
   callback && callback()
 }
文档

以上,我们的组件封装完成,但是为了方便组件分享和使用,最好还是要编写相应的使用文档,这里不做详细展开,有需要可以自行搜索如何优雅的实现组件的文档编写。编写文档后,才适合发布到npm上,怎么发布到npm上,本文也不多涉及。

总结

本文主要是基于vue进行组件的简单封装,封装也是从用户使用的角度上进行思考,自上而下的进行需求的定义,然后再基于demo进行封装优化,考虑一定的使用场景,实现了一些特殊的功能。但是当我们想让我们的组件在其他框架里面使用的时候vue的组件化就不满足了,那么如何使我们的组件框架无关呢,当然是原生实现。那么我们的下一篇即,原生组件化。