mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-05-18 11:37:31 +08:00
fix(player): 静音保留原音量,解除后可恢复
- playerCore 新增持久化 isMuted 状态及 setMuted/toggleMute,静音时音频输出置 0 但 volume 保持不变 - 音量 > 0 时自动解除静音 - useVolumeControl 移除原 0↔30 切换;滑块/百分比展示真实音量,图标反映静音态 - 三个播放栏的音量滑块在静音时 disabled;PlayBar 百分比文字同步置灰(仅文字颜色)
This commit is contained in:
@@ -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();
|
||||||
|
|||||||
@@ -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,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,
|
||||||
|
|||||||
@@ -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) ==========
|
||||||
|
|||||||
@@ -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'
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user