我的网页上有一个音频元素,我正在使用 CSS 和 VueJS 创建一个循环进度指示器来显示已播放的音频量。一切都按照我想要的方式进行,随着音频的播放,我看到进度在变化。
我遇到的问题是当我想将音频移动到新位置时,我无法获取更新进度。
非常感谢任何帮助或建议。
我认为我应该使用
animation-range
并为其绑定一个值,但这不起作用。
<template>
<div ref="mainCover" id="main_cover" @click="onClick">
<div class="progress blue">
<span class="progress-left">
<span class="progress-bar"></span>
</span>
<span class="progress-right">
<span class="progress-bar"></span>
</span>
<div class="progress-value">90%</div>
</div>
</div>
</template>
<script setup>
import { defineProps, ref, onMounted, inject } from 'vue'
import { useEventListener } from '@vueuse/core';
const { duration } = defineProps({
duration: {
type: String,
required: false,
},
})
let isPlaying = ref('paused')
let startPosition = ref(0 + '%')
eventBus.on('playing', () => {
isPlaying.value = 'running'
})
eventBus.on('paused', () => {
isPlaying.value = 'paused'
})
const halfDuration = ref((duration / 2) + 's')
eventBus.on('timeupdate', (currentTime) => {
startPosition.value = (currentTime / duration) * 100 + '%'
})
const mainCover = ref()
</script>
<style lang="css" scoped>
.progress{
width: 150px;
height: 150px;
line-height: 150px;
background: none;
margin: 0 auto;
box-shadow: none;
position: relative;
}
.progress:after{
content: "";
width: 100%;
height: 100%;
border-radius: 50%;
border: 5px solid #f2f5f5;
position: absolute;
top: 0;
left: 0;
}
.progress > span{
width: 50%;
height: 100%;
overflow: hidden;
position: absolute;
top: 0;
z-index: 1;
}
.progress .progress-left{
left: 0;
}
.progress .progress-bar{
width: 100%;
height: 100%;
background: none;
border-width: 5px;
border-style: solid;
position: absolute;
top: 0;
}
.progress .progress-left .progress-bar{
left: 100%;
border-top-right-radius: 80px;
border-bottom-right-radius: 80px;
border-left: 0;
-webkit-transform-origin: center left;
transform-origin: center left;
}
.progress .progress-right{
right: 0;
}
.progress .progress-right .progress-bar{
left: -100%;
border-top-left-radius: 80px;
border-bottom-left-radius: 80px;
border-right: 0;
-webkit-transform-origin: center right;
transform-origin: center right;
animation: loading-1 v-bind('halfDuration') linear forwards;
animation-play-state: v-bind('isPlaying');
animation-range: v-bind('startPosition');
}
.progress .progress-value{
width: 100%;
height: 100%;
font-size: 24px;
color: rgb(250, 245, 245);
text-align: center;
position: absolute;
}
.progress.blue .progress-bar{
border-color: #26abfd;
}
.progress.blue .progress-left .progress-bar{
animation: loading-1 v-bind('halfDuration') linear forwards v-bind('halfDuration');
animation-play-state: v-bind('isPlaying');
animation-range: v-bind('startPosition');
}
@keyframes loading-1{
0%{
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100%{
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
}
}
</style>
在得到我需要但不完全的结果后,我决定做更多研究并发现一篇很棒的文章https://www.30secondsofcode.org/css/s/circular-progress-bar/
我用文章中的内容替换了 HTML 和 CSS,并且能够更新我的代码,使其完全符合我的要求。
附上我更新的代码。
<template>
<svg width="150" height="150" viewBox="0 0 150 150" class="circular-progress" @click="onClick">
<circle class="bg"></circle>
<circle class="fg"></circle>
</svg>
</template>
<script setup>
import { defineProps, ref, onMounted, inject } from 'vue'
import { useEventListener } from '@vueuse/core';
const { duration } = defineProps({
duration: {
type: String,
required: false,
},
})
const eventBus = inject('eventBus')
const animationDuration = ref(duration + 's')
const animationDelay = ref(0 + 's')
const animationPlayState = ref('paused')
eventBus.on('playing', () => {
animationPlayState.value = 'running'
})
eventBus.on('paused', () => {
animationPlayState.value = 'paused'
})
eventBus.on('seeking', (currentTime) => {
animationDelay.value = ((duration - (duration - currentTime)) * -1) + 's'
})
eventBus.on('timeupdate', (currentTime) => {
if(currentTime === 0) {
animationDelay.value = 0
}
})
const onClick = () => {
eventBus.emit('playPauseClick')
}
</script>
<style lang="css" scoped>
.circular-progress {
--size: 150px;
--half-size: calc(var(--size) / 2);
--stroke-width: 5px;
--radius: calc((var(--size) - var(--stroke-width)) / 2);
--circumference: calc(var(--radius) * pi * 2);
--dash: calc((var(--progress) * var(--circumference)) / 100);
animation: progress-animation v-bind('animationDuration') linear v-bind('animationDelay') 1 forwards;
animation-play-state: v-bind('animationPlayState')
}
.circular-progress circle {
cx: var(--half-size);
cy: var(--half-size);
r: var(--radius);
stroke-width: var(--stroke-width);
fill: none;
stroke-linecap: butt;
}
.circular-progress circle.bg {
stroke: #ddd;
}
.circular-progress circle.fg {
transform: rotate(-90deg);
transform-origin: var(--half-size) var(--half-size);
stroke-dasharray: var(--dash) calc(var(--circumference) - var(--dash));
transition: stroke-dasharray 0.3s linear 0s;
stroke: #5394fd;
}
@property --progress {
syntax: "<number>";
inherits: false;
initial-value: 0;
}
@keyframes progress-animation {
from {
--progress: 0;
}
to {
--progress: 100;
}
}
</style>