music / src /components /player /PlayModeToggle.vue
ahutchen's picture
fix
40f23a9
<template>
<button
class="play-mode-toggle"
:class="{ 'active': isActive }"
@click="toggleMode"
:title="modeText"
>
<i :class="modeIcon" class="mode-icon"></i>
<span class="mode-text" v-if="showText">{{ modeText }}</span>
</button>
</template>
<script setup>
import { computed } from 'vue'
import { usePlayerStore } from '@/stores/player'
const props = defineProps({
// 是否显示文字
showText: {
type: Boolean,
default: false
},
// 是否激活状态
isActive: {
type: Boolean,
default: false
},
// 按钮大小
size: {
type: String,
default: 'medium', // small, medium, large
validator: (value) => ['small', 'medium', 'large'].includes(value)
}
})
const emit = defineEmits(['change'])
const playerStore = usePlayerStore()
// 播放模式图标映射
const modeIcon = computed(() => {
const iconMap = {
'list': 'fas fa-list-ul',
'loop': 'fas fa-redo-alt',
'random': 'fas fa-random'
}
return iconMap[playerStore.playMode] || iconMap.list
})
// 播放模式文本映射
const modeText = computed(() => {
const textMap = {
'list': '列表循环',
'loop': '单曲循环',
'random': '随机播放'
}
return textMap[playerStore.playMode] || textMap.list
})
// 切换播放模式
const toggleMode = () => {
const modes = ['list', 'loop', 'random']
const currentIndex = modes.indexOf(playerStore.playMode)
const nextIndex = (currentIndex + 1) % modes.length
const nextMode = modes[nextIndex]
playerStore.setPlayMode(nextMode)
emit('change', nextMode)
}
</script>
<style scoped>
.play-mode-toggle {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
border: none;
background: transparent;
color: var(--text-secondary);
cursor: pointer;
transition: var(--transition-fast);
border-radius: 50%;
padding: 8px;
min-width: 44px;
min-height: 44px;
}
.play-mode-toggle:hover {
color: var(--text-primary);
background: rgba(255, 255, 255, 0.1);
}
.play-mode-toggle.active {
color: var(--accent-red);
}
.play-mode-toggle.active:hover {
color: var(--accent-red-hover);
}
.mode-icon {
font-size: 16px;
transition: var(--transition-fast);
}
.mode-text {
font-size: 12px;
font-weight: 500;
white-space: nowrap;
}
/* 尺寸变化 */
.play-mode-toggle[data-size="small"] {
min-width: 36px;
min-height: 36px;
padding: 6px;
}
.play-mode-toggle[data-size="small"] .mode-icon {
font-size: 14px;
}
.play-mode-toggle[data-size="small"] .mode-text {
font-size: 11px;
}
.play-mode-toggle[data-size="large"] {
min-width: 52px;
min-height: 52px;
padding: 10px;
}
.play-mode-toggle[data-size="large"] .mode-icon {
font-size: 18px;
}
.play-mode-toggle[data-size="large"] .mode-text {
font-size: 13px;
}
/* 响应式 */
@media (max-width: 375px) {
.play-mode-toggle {
min-width: 40px;
min-height: 40px;
padding: 6px;
}
.mode-icon {
font-size: 14px;
}
.mode-text {
font-size: 11px;
}
}
/* 动画效果 */
.play-mode-toggle:active {
transform: scale(0.95);
}
/* 特殊模式动画 */
.play-mode-toggle .fa-random {
animation: random-pulse 2s ease-in-out infinite;
}
@keyframes random-pulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.6;
}
}
.play-mode-toggle .fa-redo-alt {
animation: loop-spin 3s linear infinite;
}
@keyframes loop-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
/* 当播放模式激活时停止动画 */
.play-mode-toggle.active .fa-random,
.play-mode-toggle.active .fa-redo-alt {
animation-play-state: paused;
}
</style>