blog-admin-web/src/views/api/aplayer/components/aplayer-controller-volume.vue
灌糖包子 c55b75686e
播放器组件重构&歌词加载问题修复
Co-authored-by: Copilot <copilot@github.com>
2026-04-28 22:15:57 +08:00

117 lines
2.9 KiB
Vue

<template>
<div class="aplayer-volume-wrap">
<icon-button
:class="`aplayer-icon-${volumeIcon}`"
:icon="volumeIcon"
@click="emit('togglemute')"
/>
<div
class="aplayer-volume-bar-wrap"
@mousedown="onBarMouseDown"
>
<div class="aplayer-volume-bar" ref="bar">
<div
class="aplayer-volume"
:style="{
height: muted ? 0 : `${Math.trunc(volume * 100)}%`,
background: theme
}"
>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue'
import IconButton from './aplayer-iconbutton.vue'
import {getElementViewTop} from '../utils'
const props = defineProps<{
volume: number
muted: boolean
theme: string
}>()
const emit = defineEmits(['setvolume', 'togglemute'])
const barHeight = 40
const volumeIcon = computed(() => {
if (props.muted || props.volume <= 0) return 'volume_off'
if (props.volume >= 1) return 'volume_up'
return 'volume_down'
})
const bar = ref<unknown>(null)
const onBarMouseDown = () => {
document.addEventListener('mousemove', onDocumentMouseMove)
document.addEventListener('mouseup', onDocumentMouseUp)
}
const onDocumentMouseMove = (e: MouseEvent) => {
let percentage = (barHeight - e.clientY + getElementViewTop(<HTMLElement>bar.value)) / barHeight
percentage = percentage > 0 ? percentage : 0
percentage = percentage < 1 ? percentage : 1
emit('setvolume', percentage)
}
const onDocumentMouseUp = (e: MouseEvent) => {
document.removeEventListener('mouseup', onDocumentMouseUp)
document.removeEventListener('mousemove', onDocumentMouseMove)
let percentage = (barHeight - e.clientY + getElementViewTop(<HTMLElement>bar.value)) / barHeight
percentage = percentage > 0 ? percentage : 0
percentage = percentage < 1 ? percentage : 1
emit('setvolume', percentage)
}
</script>
<style lang="less" scoped>
.aplayer-volume-wrap {
position: relative;
cursor: pointer;
z-index: 0;
&:hover .aplayer-volume-bar-wrap {
display: block;
}
.aplayer-volume-bar-wrap {
display: none;
position: absolute;
bottom: 15px;
left: -4px;
right: -4px;
height: 40px;
z-index: -1;
transition: all .2s ease;
&::after {
content: '';
position: absolute;
bottom: -16px;
left: 0;
right: 0;
height: 62px;
background-color: #fff;
box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.07), 0 0 5px 0 rgba(0, 0, 0, 0.1);
}
.aplayer-volume-bar {
position: absolute;
bottom: 0;
left: 11px;
width: 5px;
height: 40px;
background: #aaa;
border-radius: 2.5px;
overflow: hidden;
z-index: 1;
.aplayer-volume {
position: absolute;
bottom: 0;
left: 0;
right: 0;
transition: height 0.1s ease, background-color .3s;
will-change: height;
}
}
}
}
</style>