fix(player): 静音保留原音量,解除后可恢复

- playerCore 新增持久化 isMuted 状态及 setMuted/toggleMute,静音时音频输出置 0 但 volume 保持不变
- 音量 > 0 时自动解除静音
- useVolumeControl 移除原 0↔30 切换;滑块/百分比展示真实音量,图标反映静音态
- 三个播放栏的音量滑块在静音时 disabled;PlayBar 百分比文字同步置灰(仅文字颜色)
This commit is contained in:
chengww
2026-04-26 21:47:11 +08:00
parent 97220761cf
commit 2b1024ca24
6 changed files with 84 additions and 16 deletions
@@ -69,6 +69,7 @@
v-model:value="volumeSlider" v-model:value="volumeSlider"
:step="0.01" :step="0.01"
:tooltip="false" :tooltip="false"
:disabled="isMuted"
vertical vertical
@wheel.prevent="handleVolumeWheel" @wheel.prevent="handleVolumeWheel"
></n-slider> ></n-slider>
@@ -145,7 +146,13 @@ const { navigateToArtist } = useArtist();
const { isPlaying: play, playMusicEvent, handleNext, handlePrev } = usePlaybackControl(); const { isPlaying: play, playMusicEvent, handleNext, handlePrev } = usePlaybackControl();
// 音量控制(统一通过 playerStore 管理) // 音量控制(统一通过 playerStore 管理)
const { volumeSlider, volumeIcon: getVolumeIcon, mute, handleVolumeWheel } = useVolumeControl(); const {
isMuted,
volumeSlider,
volumeIcon: getVolumeIcon,
mute,
handleVolumeWheel
} = useVolumeControl();
// 收藏 // 收藏
const { isFavorite, toggleFavorite } = useFavorite(); const { isFavorite, toggleFavorite } = useFavorite();
+21 -3
View File
@@ -99,8 +99,16 @@
<i class="iconfont" :class="getVolumeIcon"></i> <i class="iconfont" :class="getVolumeIcon"></i>
</div> </div>
<div class="volume-slider"> <div class="volume-slider">
<div class="volume-percentage">{{ Math.round(volumeSlider) }}%</div> <div class="volume-percentage" :class="{ 'volume-percentage-disabled': isMuted }">
<n-slider v-model:value="volumeSlider" :step="0.01" :tooltip="false" vertical></n-slider> {{ Math.round(volumeSlider) }}%
</div>
<n-slider
v-model:value="volumeSlider"
:step="0.01"
:tooltip="false"
:disabled="isMuted"
vertical
></n-slider>
</div> </div>
</div> </div>
<n-tooltip v-if="!isMobile" trigger="hover" :z-index="9999999"> <n-tooltip v-if="!isMobile" trigger="hover" :z-index="9999999">
@@ -198,7 +206,13 @@ const { t } = useI18n();
const { isPlaying: play, playMusicEvent, handleNext, handlePrev } = usePlaybackControl(); const { isPlaying: play, playMusicEvent, handleNext, handlePrev } = usePlaybackControl();
// 音量控制 // 音量控制
const { volumeSlider, volumeIcon: getVolumeIcon, mute, handleVolumeWheel } = useVolumeControl(); const {
isMuted,
volumeSlider,
volumeIcon: getVolumeIcon,
mute,
handleVolumeWheel
} = useVolumeControl();
// 收藏 // 收藏
const { isFavorite, toggleFavorite } = useFavorite(); const { isFavorite, toggleFavorite } = useFavorite();
@@ -382,6 +396,10 @@ const openPlayListDrawer = () => {
@apply border border-gray-200 dark:border-gray-700; @apply border border-gray-200 dark:border-gray-700;
@apply text-gray-800 dark:text-white; @apply text-gray-800 dark:text-white;
white-space: nowrap; white-space: nowrap;
&.volume-percentage-disabled {
@apply text-gray-400 dark:text-gray-500;
}
} }
} }
} }
@@ -68,6 +68,7 @@
v-model:value="volumeSlider" v-model:value="volumeSlider"
:step="1" :step="1"
:tooltip="false" :tooltip="false"
:disabled="isMuted"
@wheel.prevent="handleVolumeWheel" @wheel.prevent="handleVolumeWheel"
></n-slider> ></n-slider>
</div> </div>
@@ -107,7 +108,13 @@ const { isPlaying: play, playMusicEvent, handleNext, handlePrev } = usePlaybackC
const { playMode, playModeIcon, togglePlayMode } = usePlayMode(); const { playMode, playModeIcon, togglePlayMode } = usePlayMode();
// 音量控制(统一通过 playerStore 管理) // 音量控制(统一通过 playerStore 管理)
const { volumeSlider, volumeIcon: getVolumeIcon, mute, handleVolumeWheel } = useVolumeControl(); const {
isMuted,
volumeSlider,
volumeIcon: getVolumeIcon,
mute,
handleVolumeWheel
} = useVolumeControl();
// 进度条控制 // 进度条控制
const isDragging = ref(false); const isDragging = ref(false);
+9 -9
View File
@@ -9,7 +9,10 @@ import { usePlayerStore } from '@/store/modules/player';
export function useVolumeControl() { export function useVolumeControl() {
const playerStore = usePlayerStore(); const playerStore = usePlayerStore();
/** 音量滑块值 (0-100) */ /** 是否静音 */
const isMuted = computed(() => playerStore.isMuted);
/** 音量滑块值 (0-100),静音时仍展示原始音量 */
const volumeSlider = computed({ const volumeSlider = computed({
get: () => playerStore.volume * 100, get: () => playerStore.volume * 100,
set: (value: number) => { set: (value: number) => {
@@ -19,21 +22,17 @@ export function useVolumeControl() {
/** 音量图标 class */ /** 音量图标 class */
const volumeIcon = computed(() => { const volumeIcon = computed(() => {
if (playerStore.volume === 0) return 'ri-volume-mute-line'; if (playerStore.isMuted || playerStore.volume === 0) return 'ri-volume-mute-line';
if (playerStore.volume <= 0.5) return 'ri-volume-down-line'; if (playerStore.volume <= 0.5) return 'ri-volume-down-line';
return 'ri-volume-up-line'; return 'ri-volume-up-line';
}); });
/** 静音切换 (0 ↔ 30%) */ /** 切换静音(保留静音前的音量) */
const mute = () => { const mute = () => {
if (volumeSlider.value === 0) { playerStore.toggleMute();
volumeSlider.value = 30;
} else {
volumeSlider.value = 0;
}
}; };
/** 鼠标滚轮调整音量 ±5% */ /** 鼠标滚轮调整音量 ±5%;静音时向上滚轮会自动解除静音 */
const handleVolumeWheel = (e: WheelEvent) => { const handleVolumeWheel = (e: WheelEvent) => {
const delta = e.deltaY < 0 ? 5 : -5; const delta = e.deltaY < 0 ? 5 : -5;
const newValue = Math.min(Math.max(volumeSlider.value + delta, 0), 100); const newValue = Math.min(Math.max(volumeSlider.value + delta, 0), 100);
@@ -41,6 +40,7 @@ export function useVolumeControl() {
}; };
return { return {
isMuted,
volumeSlider, volumeSlider,
volumeIcon, volumeIcon,
mute, mute,
+4
View File
@@ -41,6 +41,7 @@ export const usePlayerStore = defineStore('player', () => {
musicFull, musicFull,
playbackRate, playbackRate,
volume, volume,
isMuted,
userPlayIntent, userPlayIntent,
isFmPlaying isFmPlaying
} = storeToRefs(playerCore); } = storeToRefs(playerCore);
@@ -97,6 +98,7 @@ export const usePlayerStore = defineStore('player', () => {
musicFull, musicFull,
playbackRate, playbackRate,
volume, volume,
isMuted,
userPlayIntent, userPlayIntent,
isFmPlaying, isFmPlaying,
@@ -113,6 +115,8 @@ export const usePlayerStore = defineStore('player', () => {
getVolume: playerCore.getVolume, getVolume: playerCore.getVolume,
increaseVolume: playerCore.increaseVolume, increaseVolume: playerCore.increaseVolume,
decreaseVolume: playerCore.decreaseVolume, decreaseVolume: playerCore.decreaseVolume,
setMuted: playerCore.setMuted,
toggleMute: playerCore.toggleMute,
handlePause: playerCore.handlePause, handlePause: playerCore.handlePause,
// ========== 播放列表管理 (Playlist) ========== // ========== 播放列表管理 (Playlist) ==========
+34 -2
View File
@@ -20,6 +20,7 @@ export const usePlayerCoreStore = defineStore(
const musicFull = ref(false); const musicFull = ref(false);
const playbackRate = ref(1.0); const playbackRate = ref(1.0);
const volume = ref(1); const volume = ref(1);
const isMuted = ref(false);
const userPlayIntent = ref(false); // 用户是否想要播放 const userPlayIntent = ref(false); // 用户是否想要播放
const isFmPlaying = ref(false); // 是否正在播放私人FM const isFmPlaying = ref(false); // 是否正在播放私人FM
@@ -65,7 +66,27 @@ export const usePlayerCoreStore = defineStore(
const setVolume = (newVolume: number) => { const setVolume = (newVolume: number) => {
const normalizedVolume = Math.max(0, Math.min(1, newVolume)); const normalizedVolume = Math.max(0, Math.min(1, newVolume));
volume.value = normalizedVolume; volume.value = normalizedVolume;
audioService.setVolume(normalizedVolume); // 用户调高音量时自动解除静音
if (isMuted.value && normalizedVolume > 0) {
isMuted.value = false;
}
audioService.setVolume(isMuted.value ? 0 : normalizedVolume);
};
/**
* 设置静音状态(不改变 volume,仅控制音频输出)
*/
const setMuted = (value: boolean) => {
if (isMuted.value === value) return;
isMuted.value = value;
audioService.setVolume(isMuted.value ? 0 : volume.value);
};
/**
* 切换静音
*/
const toggleMute = () => {
setMuted(!isMuted.value);
}; };
/** /**
@@ -169,6 +190,7 @@ export const usePlayerCoreStore = defineStore(
musicFull, musicFull,
playbackRate, playbackRate,
volume, volume,
isMuted,
userPlayIntent, userPlayIntent,
isFmPlaying, isFmPlaying,
audioOutputDeviceId, audioOutputDeviceId,
@@ -187,6 +209,8 @@ export const usePlayerCoreStore = defineStore(
getVolume, getVolume,
increaseVolume, increaseVolume,
decreaseVolume, decreaseVolume,
setMuted,
toggleMute,
handlePause, handlePause,
refreshAudioDevices, refreshAudioDevices,
setAudioOutputDevice, setAudioOutputDevice,
@@ -197,7 +221,15 @@ export const usePlayerCoreStore = defineStore(
persist: { persist: {
key: 'player-core-store', key: 'player-core-store',
storage: localStorage, storage: localStorage,
pick: ['playMusic', 'playMusicUrl', 'playbackRate', 'volume', 'isPlay', 'audioOutputDeviceId'] pick: [
'playMusic',
'playMusicUrl',
'playbackRate',
'volume',
'isMuted',
'isPlay',
'audioOutputDeviceId'
]
} }
} }
); );