mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-05-17 02:07:29 +08:00
feat: 一系列播放优化
This commit is contained in:
@@ -76,7 +76,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useMessage } from 'naive-ui';
|
||||
import { ref, watch } from 'vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import { CacheManager } from '@/api/musicParser';
|
||||
@@ -96,7 +96,7 @@ const currentReparsingSource = ref<Platform | null>(null);
|
||||
// 实际存储选中音源的值
|
||||
const selectedSourcesValue = ref<Platform[]>([]);
|
||||
|
||||
const isReparse = ref(localStorage.getItem(`song_source_${String(playMusic.value.id)}`) !== null);
|
||||
const isReparse = computed(() => selectedSourcesValue.value.length > 0);
|
||||
|
||||
// 可选音源列表
|
||||
const musicSourceOptions = ref([
|
||||
@@ -121,7 +121,8 @@ const getSourceIcon = (source: Platform) => {
|
||||
joox: 'ri-disc-fill',
|
||||
pyncmd: 'ri-netease-cloud-music-fill',
|
||||
bilibili: 'ri-bilibili-fill',
|
||||
gdmusic: 'ri-google-fill'
|
||||
gdmusic: 'ri-google-fill',
|
||||
kuwo: 'ri-music-fill'
|
||||
};
|
||||
|
||||
return iconMap[source] || 'ri-music-2-fill';
|
||||
@@ -148,7 +149,6 @@ const initSelectedSources = () => {
|
||||
const clearCustomSource = () => {
|
||||
localStorage.removeItem(`song_source_${String(playMusic.value.id)}`);
|
||||
selectedSourcesValue.value = [];
|
||||
isReparse.value = false;
|
||||
};
|
||||
|
||||
// 直接重新解析当前歌曲
|
||||
@@ -174,7 +174,7 @@ const directReparseMusic = async (source: Platform) => {
|
||||
JSON.stringify(selectedSourcesValue.value)
|
||||
);
|
||||
|
||||
const success = await playerStore.reparseCurrentSong(source);
|
||||
const success = await playerStore.reparseCurrentSong(source, false);
|
||||
|
||||
if (success) {
|
||||
message.success(t('player.reparse.success'));
|
||||
@@ -221,7 +221,10 @@ watch(
|
||||
console.log('URL已过期,自动应用自定义音源重新加载');
|
||||
try {
|
||||
isReparsing.value = true;
|
||||
const success = await playerStore.reparseCurrentSong(sources[0]);
|
||||
const songId = String(playMusic.value.id);
|
||||
const sourceType = localStorage.getItem(`song_source_type_${songId}`);
|
||||
const isAuto = sourceType === 'auto';
|
||||
const success = await playerStore.reparseCurrentSong(sources[0], isAuto);
|
||||
if (!success) {
|
||||
message.error(t('player.reparse.failed'));
|
||||
}
|
||||
|
||||
@@ -4,14 +4,19 @@
|
||||
<!-- 顶部进度条和时间 -->
|
||||
<div class="top-section">
|
||||
<!-- 进度条 -->
|
||||
<div class="progress-bar" @click="handleProgressClick">
|
||||
<div
|
||||
class="progress-bar"
|
||||
:class="{ 'is-dragging': isDragging }"
|
||||
@mousedown="handleProgressMouseDown"
|
||||
@click.stop="handleProgressClick"
|
||||
>
|
||||
<div class="progress-track"></div>
|
||||
<div class="progress-fill" :style="{ width: `${(nowTime / allTime) * 100}%` }"></div>
|
||||
<div class="progress-fill" :style="{ width: `${progressPercentage}%` }"></div>
|
||||
</div>
|
||||
|
||||
<!-- 时间显示 -->
|
||||
<div class="time-display">
|
||||
<span class="current-time">{{ formatTime(nowTime) }}</span>
|
||||
<span class="current-time">{{ formatTime(displayTime) }}</span>
|
||||
<span class="total-time">{{ formatTime(allTime) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -150,11 +155,81 @@ const playMusicEvent = async () => {
|
||||
};
|
||||
|
||||
// 进度条控制
|
||||
const isDragging = ref(false);
|
||||
const dragProgress = ref(0); // 拖拽时的预览进度 (0-100)
|
||||
|
||||
// 计算当前显示的进度百分比
|
||||
const progressPercentage = computed(() => {
|
||||
if (isDragging.value) {
|
||||
return dragProgress.value;
|
||||
}
|
||||
if (allTime.value === 0) return 0;
|
||||
return (nowTime.value / allTime.value) * 100;
|
||||
});
|
||||
|
||||
// 计算显示的时间
|
||||
const displayTime = computed(() => {
|
||||
if (isDragging.value) {
|
||||
return (dragProgress.value / 100) * allTime.value;
|
||||
}
|
||||
return nowTime.value;
|
||||
});
|
||||
|
||||
// 计算进度百分比的辅助函数
|
||||
const calculateProgress = (clientX: number, element: HTMLElement): number => {
|
||||
const rect = element.getBoundingClientRect();
|
||||
const percent = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
|
||||
return percent * 100;
|
||||
};
|
||||
|
||||
// 更新音频进度
|
||||
const seekToProgress = (percentage: number) => {
|
||||
const targetTime = (percentage / 100) * allTime.value;
|
||||
audioService.seek(targetTime);
|
||||
// 不立即更新 nowTime,让音频服务的回调来更新,避免不同步
|
||||
};
|
||||
|
||||
// 鼠标按下开始拖拽
|
||||
const handleProgressMouseDown = (e: MouseEvent) => {
|
||||
if (e.button !== 0) return; // 只响应左键
|
||||
|
||||
const target = e.currentTarget as HTMLElement;
|
||||
isDragging.value = true;
|
||||
dragProgress.value = calculateProgress(e.clientX, target);
|
||||
|
||||
// 添加全局鼠标移动和释放监听
|
||||
const handleMouseMove = (moveEvent: MouseEvent) => {
|
||||
if (isDragging.value) {
|
||||
dragProgress.value = calculateProgress(moveEvent.clientX, target);
|
||||
}
|
||||
};
|
||||
|
||||
const handleMouseUp = () => {
|
||||
if (isDragging.value) {
|
||||
// 拖拽结束,执行跳转
|
||||
seekToProgress(dragProgress.value);
|
||||
isDragging.value = false;
|
||||
}
|
||||
// 移除事件监听
|
||||
document.removeEventListener('mousemove', handleMouseMove);
|
||||
document.removeEventListener('mouseup', handleMouseUp);
|
||||
};
|
||||
|
||||
document.addEventListener('mousemove', handleMouseMove);
|
||||
document.addEventListener('mouseup', handleMouseUp);
|
||||
|
||||
// 防止文本选择
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
// 点击进度条跳转
|
||||
const handleProgressClick = (e: MouseEvent) => {
|
||||
const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
|
||||
const percent = (e.clientX - rect.left) / rect.width;
|
||||
audioService.seek(allTime.value * percent);
|
||||
nowTime.value = allTime.value * percent;
|
||||
// 如果正在拖拽,不处理点击事件
|
||||
if (isDragging.value) return;
|
||||
|
||||
const target = e.currentTarget as HTMLElement;
|
||||
const percentage = calculateProgress(e.clientX, target);
|
||||
seekToProgress(percentage);
|
||||
};
|
||||
|
||||
// 格式化时间
|
||||
@@ -348,6 +423,7 @@ onMounted(() => {
|
||||
|
||||
.progress-bar {
|
||||
@apply relative cursor-pointer h-2 mb-2 w-full;
|
||||
user-select: none;
|
||||
|
||||
.progress-track {
|
||||
@apply absolute inset-0 rounded-full transition-all duration-150;
|
||||
@@ -364,10 +440,6 @@ onMounted(() => {
|
||||
.progress-track {
|
||||
background-color: var(--track-color-hover);
|
||||
}
|
||||
.progress-track,
|
||||
.progress-fill {
|
||||
@apply h-full;
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
box-shadow: 0 0 12px var(--fill-color-transparent);
|
||||
|
||||
Reference in New Issue
Block a user