feat: 优化音乐列表加载和播放逻辑,增强性能和用户体验

This commit is contained in:
alger
2025-02-28 19:52:00 +08:00
parent 87a0ceb5b0
commit c703d9c197
5 changed files with 92 additions and 13 deletions
+6 -2
View File
@@ -88,11 +88,15 @@ onMounted(() => {
homeRouter.filter((item) => item.meta.isMobile) homeRouter.filter((item) => item.meta.isMobile)
); );
} }
window.electron.ipcRenderer.on('set-language', handleSetLanguage); if (isElectron) {
window.electron.ipcRenderer.on('set-language', handleSetLanguage);
}
}); });
onUnmounted(() => { onUnmounted(() => {
window.electron.ipcRenderer.removeListener('set-language', handleSetLanguage); if (isElectron) {
window.electron.ipcRenderer.removeListener('set-language', handleSetLanguage);
}
}); });
</script> </script>
+77 -10
View File
@@ -119,10 +119,11 @@ const props = withDefaults(
const emit = defineEmits(['update:show', 'update:loading', 'remove-song']); const emit = defineEmits(['update:show', 'update:loading', 'remove-song']);
const page = ref(0); const page = ref(0);
const pageSize = 20; const pageSize = 40;
const isLoadingMore = ref(false); const isLoadingMore = ref(false);
const displayedSongs = ref<any[]>([]); const displayedSongs = ref<any[]>([]);
const loadingList = ref(false); const loadingList = ref(false);
const loadedIds = ref(new Set<number>()); // 用于追踪已加载的歌曲ID
// 计算总数 // 计算总数
const total = computed(() => { const total = computed(() => {
@@ -144,11 +145,31 @@ const formatDetail = computed(() => (detail: any) => {
return detail; return detail;
}); });
const loadAllSongs = () => {
return new Promise((resolve, reject) => {
const loadNext = () => {
if (displayedSongs.value.length >= total.value) {
resolve(true);
return;
}
loadMoreSongs()
.then(() => {
// 使用 setTimeout 避免阻塞主线程
setTimeout(loadNext, 100);
})
.catch(reject);
};
loadNext();
});
};
const handlePlay = () => { const handlePlay = () => {
const tracks = props.songList || []; // 立即使用当前已加载的歌曲开始播放
store.commit( store.commit(
'setPlayList', 'setPlayList',
tracks.map((item) => ({ displayedSongs.value.map((item) => ({
...item, ...item,
picUrl: item.al.picUrl, picUrl: item.al.picUrl,
song: { song: {
@@ -156,6 +177,30 @@ const handlePlay = () => {
} }
})) }))
); );
// 如果还有未加载的歌曲,在后台异步加载
if (displayedSongs.value.length < total.value) {
setTimeout(() => {
loadAllSongs()
.then(() => {
// 加载完成后更新完整播放列表
store.commit(
'setPlayList',
displayedSongs.value.map((item) => ({
...item,
picUrl: item.al.picUrl,
song: {
artists: item.ar
}
}))
);
})
.catch((error) => {
console.error('加载完整播放列表失败:', error);
window.$message.warning(t('common.partialLoadFailed'));
});
}, 2000);
}
}; };
const close = () => { const close = () => {
@@ -172,23 +217,32 @@ const loadMoreSongs = async () => {
// 如果有 trackIds,需要分批请求歌曲详情 // 如果有 trackIds,需要分批请求歌曲详情
const start = page.value * pageSize; const start = page.value * pageSize;
const end = Math.min((page.value + 1) * pageSize, total.value); const end = Math.min((page.value + 1) * pageSize, total.value);
const trackIds = props.listInfo.trackIds.slice(start, end).map((item) => item.id);
if (trackIds.length > 0) { // 从 trackIds 中获取需要加载的 ID
const { data } = await getMusicDetail(trackIds); const trackIdsToLoad = props.listInfo.trackIds
.slice(start, end)
.map((item) => item.id)
.filter((id) => !loadedIds.value.has(id));
if (trackIdsToLoad.length > 0) {
const { data } = await getMusicDetail(trackIdsToLoad);
// 更新已加载ID集合
data.songs.forEach((song) => loadedIds.value.add(song.id));
displayedSongs.value = [...displayedSongs.value, ...data.songs]; displayedSongs.value = [...displayedSongs.value, ...data.songs];
page.value++;
} }
page.value++;
} else { } else {
// 如果没有 trackIds,直接使用 songList 分页 // 如果没有 trackIds,直接使用 songList 分页
const start = page.value * pageSize; const start = page.value * pageSize;
const end = Math.min((page.value + 1) * pageSize, props.songList.length); const end = Math.min((page.value + 1) * pageSize, props.songList.length);
const newSongs = props.songList.slice(start, end); const newSongs = props.songList.slice(start, end);
newSongs.forEach((song) => loadedIds.value.add(song.id));
displayedSongs.value = [...displayedSongs.value, ...newSongs]; displayedSongs.value = [...displayedSongs.value, ...newSongs];
page.value++; page.value++;
} }
} catch (error) { } catch (error) {
console.error('加载歌曲失败:', error); console.error('加载歌曲失败:', error);
throw error;
} finally { } finally {
isLoadingMore.value = false; isLoadingMore.value = false;
loadingList.value = false; loadingList.value = false;
@@ -226,10 +280,23 @@ watch(
() => props.songList, () => props.songList,
(newSongs) => { (newSongs) => {
page.value = 0; page.value = 0;
displayedSongs.value = newSongs.slice(0, pageSize); loadedIds.value.clear();
if (newSongs.length > pageSize) { displayedSongs.value = [];
page.value = 1;
// 优先加载 songList 的数据
if (newSongs.length > 0) {
displayedSongs.value = newSongs;
// 记录已加载的歌曲ID
newSongs.forEach((song) => loadedIds.value.add(song.id));
// 计算起始页码
page.value = Math.ceil(newSongs.length / pageSize);
} }
// 如果还有更多歌曲需要加载(通过 trackIds),则继续加载
if (props.listInfo?.trackIds && total.value > newSongs.length) {
loadMoreSongs();
}
loadingList.value = false; loadingList.value = false;
}, },
{ immediate: true } { immediate: true }
+1
View File
@@ -329,6 +329,7 @@ const actions = {
commit('setCurrentArtistId', id); commit('setCurrentArtistId', id);
}, },
async initializeSystemFonts({ commit, state }) { async initializeSystemFonts({ commit, state }) {
if (!isElectron) return;
// 如果已经有字体列表(不只是默认字体),则不重复获取 // 如果已经有字体列表(不只是默认字体),则不重复获取
if (state.systemFonts.length > 1) return; if (state.systemFonts.length > 1) return;
+7
View File
@@ -59,6 +59,13 @@ export const formatNumber = (num: string | number) => {
}; };
export const getImgUrl = (url: string | undefined, size: string = '') => { export const getImgUrl = (url: string | undefined, size: string = '') => {
if (!url) return '';
if (url.includes('thumbnail')) {
// 只替换最后一个 thumbnail 参数的尺寸
return url.replace(/thumbnail=\d+y\d+(?!.*thumbnail)/, `thumbnail=${size}`);
}
const imgUrl = `${url}?param=${size}`; const imgUrl = `${url}?param=${size}`;
return imgUrl; return imgUrl;
}; };
+1 -1
View File
@@ -36,7 +36,7 @@
<div class="recommend-item-img"> <div class="recommend-item-img">
<n-image <n-image
class="recommend-item-img-img" class="recommend-item-img-img"
:src="getImgUrl(item.picUrl || item.coverImgUrl, '200y200')" :src="getImgUrl(item.picUrl || item.coverImgUrl, '300y300')"
width="200" width="200"
height="200" height="200"
lazy lazy