perf: 视频播放器优化

This commit is contained in:
pipipi-pikachu 2021-09-04 10:29:45 +08:00
parent f3a4666ce5
commit 8c49e29fbc
5 changed files with 77 additions and 11 deletions

View File

@ -4,7 +4,7 @@ module.exports = {
extends: 'stylelint-config-standard', extends: 'stylelint-config-standard',
rules: { rules: {
'indentation': 2, 'indentation': 2,
'max-nesting-depth': 4, 'max-nesting-depth': 5,
'max-empty-lines': null, 'max-empty-lines': null,
'no-eol-whitespace': true, 'no-eol-whitespace': true,
'no-missing-end-of-source-newline': null, 'no-missing-end-of-source-newline': null,

View File

@ -184,7 +184,7 @@ A. 本项目只提供最基础的视频能力正常状态下可以播放video
# 💻 贡献代码 # 💻 贡献代码
首先感谢每一位关注本项目的朋友,由于本人时间精力有限,且目前项目规模不大,暂时没有团队化开发维护本项目的打算。但非常欢迎每一位对本项目感兴趣的朋友贡献代码。 首先感谢每一位关注本项目的朋友,非常欢迎每一位对本项目感兴趣的朋友贡献代码。
### 具体参考如下: ### 具体参考如下:
- fork 源码,下载到本地并运行项目 - fork 源码,下载到本地并运行项目
- 修改代码并进行自我测试后提交修改到 github - 修改代码并进行自我测试后提交修改到 github

View File

@ -88,7 +88,7 @@ import {
VolumeMute, VolumeMute,
VolumeNotice, VolumeNotice,
VolumeSmall, VolumeSmall,
LoopOnce, CycleOne,
VideoTwo, VideoTwo,
} from '@icon-park/vue-next' } from '@icon-park/vue-next'
@ -208,6 +208,6 @@ export default {
app.component('IconVolumeMute', VolumeMute) app.component('IconVolumeMute', VolumeMute)
app.component('IconVolumeNotice', VolumeNotice) app.component('IconVolumeNotice', VolumeNotice)
app.component('IconVolumeSmall', VolumeSmall) app.component('IconVolumeSmall', VolumeSmall)
app.component('IconLoopOnce', LoopOnce) app.component('IconCycleOne', CycleOne)
} }
} }

View File

@ -71,9 +71,23 @@
</div> </div>
<div class="icons icons-right"> <div class="icons icons-right">
<div class="speed">
<div class="icon speed-icon">
<span class="icon-content" @click="speedMenuVisible = !speedMenuVisible">倍速</span>
<div class="speed-menu" v-if="speedMenuVisible" @mouseleave="speedMenuVisible = false">
<div
class="speed-menu-item"
:class="{ 'active': item.value === playbackRate }"
v-for="item in speedOptions"
:key="item.label"
@click="speed(item.value)"
>{{item.label}}</div>
</div>
</div>
</div>
<div class="loop" @click="toggleLoop()"> <div class="loop" @click="toggleLoop()">
<div class="icon loop-icon" :class="{ 'active': loop }"> <div class="icon loop-icon" :class="{ 'active': loop }">
<span class="icon-content"><IconLoopOnce /></span> <span class="icon-content"><IconCycleOne /></span>
</div> </div>
</div> </div>
</div> </div>
@ -155,6 +169,7 @@ export default defineComponent({
const loaded = ref(0) const loaded = ref(0)
const loop = ref(false) const loop = ref(false)
const bezelTransition = ref(false) const bezelTransition = ref(false)
const playbackRate = ref(1)
const playBarTimeVisible = ref(false) const playBarTimeVisible = ref(false)
const playBarTime = ref('00:00') const playBarTime = ref('00:00')
@ -166,6 +181,16 @@ export default defineComponent({
const loadedBarWidth = computed(() => loaded.value / duration.value * 100 + '%') const loadedBarWidth = computed(() => loaded.value / duration.value * 100 + '%')
const volumeBarWidth = computed(() => volume.value * 100 + '%') const volumeBarWidth = computed(() => volume.value * 100 + '%')
const speedMenuVisible = ref(false)
const speedOptions = [
{ label: '2x', value: 2 },
{ label: '1.5x', value: 1.5 },
{ label: '1.25x', value: 1.25 },
{ label: '1x', value: 1 },
{ label: '0.75x', value: 0.75 },
{ label: '0.5x', value: 0.5 },
]
const seek = (time: number) => { const seek = (time: number) => {
if (!videoRef.value) return if (!videoRef.value) return
@ -208,6 +233,11 @@ export default defineComponent({
if (videoRef.value.muted && percentage !== 0) videoRef.value.muted = false if (videoRef.value.muted && percentage !== 0) videoRef.value.muted = false
} }
const speed = (rate: number) => {
if (videoRef.value) videoRef.value.playbackRate = rate
playbackRate.value = rate
}
const handleDurationchange = () => { const handleDurationchange = () => {
duration.value = videoRef.value?.duration || 0 duration.value = videoRef.value?.duration || 0
} }
@ -354,11 +384,15 @@ export default defineComponent({
volumeBarWidth, volumeBarWidth,
hideController, hideController,
bezelTransition, bezelTransition,
playbackRate,
speedMenuVisible,
speedOptions,
seek, seek,
play, play,
pause, pause,
toggle, toggle,
setVolume, setVolume,
speed,
handleDurationchange, handleDurationchange,
handleTimeupdate, handleTimeupdate,
handleEnded, handleEnded,

View File

@ -135,7 +135,7 @@
bottom: 0; bottom: 0;
height: 3px; height: 3px;
will-change: width; will-change: width;
background-color: $themeColor; background-color: #fff;
.thumb { .thumb {
position: absolute; position: absolute;
@ -149,7 +149,7 @@
cursor: pointer; cursor: pointer;
transition: all 0.3s ease-in-out; transition: all 0.3s ease-in-out;
transform: scale(0); transform: scale(0);
background-color: $themeColor; background-color: #fff;
} }
} }
} }
@ -179,7 +179,7 @@
cursor: pointer; cursor: pointer;
display: flex; display: flex;
align-items: center; align-items: center;
font-size: 22px; font-size: 20px;
&.play-icon { &.play-icon {
font-size: 26px; font-size: 26px;
@ -190,8 +190,40 @@
opacity: 0.8; opacity: 0.8;
color: #fff; color: #fff;
} }
&.loop-icon {
.icon-content {
opacity: 0.6;
}
}
&.speed-icon {
font-size: 12px;
position: relative;
}
.speed-menu {
width: 70px;
position: absolute;
bottom: 30px;
left: -23px;
background-color: #22211b;
padding: 5px 0;
color: #ddd;
.speed-menu-item {
padding: 8px 0;
text-align: center;
&:hover {
background-color: #393833;
color: #fff;
}
&.active {
font-weight: 700;
color: #fff;
}
}
}
&.active .icon-content { &.active .icon-content {
color: $themeColor;
opacity: 1; opacity: 1;
} }
&:hover .icon-content { &:hover .icon-content {
@ -243,7 +275,7 @@
height: 100%; height: 100%;
transition: all 0.1s ease; transition: all 0.1s ease;
will-change: width; will-change: width;
background-color: $themeColor; background-color: #fff;
.thumb { .thumb {
position: absolute; position: absolute;
@ -257,7 +289,7 @@
cursor: pointer; cursor: pointer;
transition: all 0.3s ease-in-out; transition: all 0.3s ease-in-out;
transform: scale(0); transform: scale(0);
background-color: $themeColor; background-color: #fff;
} }
} }
} }