组件封装
无论是日常生活中,还是工作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和三个方法即可
- 定义两个属性
//
props: {
src: {
type: String
},
poster: {
type: String
}
},
同时同步到模板上
- 定义三个方法,方法由于是通过$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的组件化就不满足了,那么如何使我们的组件框架无关呢,当然是原生实现。那么我们的下一篇即,原生组件化。