Skip to content

Commit b2ddb9f

Browse files
committed
✨ feat: 优化随机播放问题 & 播放页字体抖动效果优化
1 parent 201186b commit b2ddb9f

File tree

5 files changed

+96
-22
lines changed

5 files changed

+96
-22
lines changed

src/components/Player/MainLyric.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ onBeforeUnmount(() => {
324324
padding: 10px 16px;
325325
transform: scale(0.86);
326326
transform-origin: left center;
327+
will-change: filter, opacity, transform;
327328
transition:
328329
filter 0.35s,
329330
opacity 0.35s,

src/stores/data.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { formatCategoryList } from "@/utils/format";
1515

1616
interface ListState {
1717
playList: SongType[];
18+
originalPlayList: SongType[];
1819
historyList: SongType[];
1920
cloudPlayList: SongType[];
2021
searchHistory: string[];
@@ -54,6 +55,8 @@ export const useDataStore = defineStore("data", {
5455
state: (): ListState => ({
5556
// 播放列表
5657
playList: [],
58+
// 原始播放列表
59+
originalPlayList: [],
5760
// 播放历史
5861
historyList: [],
5962
// 搜索历史
@@ -157,6 +160,29 @@ export const useDataStore = defineStore("data", {
157160
throw error;
158161
}
159162
},
163+
// 保存原始播放列表
164+
async setOriginalPlayList(data: SongType[]): Promise<void> {
165+
const snapshot = cloneDeep(data);
166+
this.originalPlayList = snapshot;
167+
await musicDB.setItem("originalPlayList", snapshot);
168+
},
169+
// 获取原始播放列表
170+
async getOriginalPlayList(): Promise<SongType[] | null> {
171+
if (Array.isArray(this.originalPlayList) && this.originalPlayList.length > 0) {
172+
return this.originalPlayList;
173+
}
174+
const data = (await musicDB.getItem("originalPlayList")) as SongType[] | null;
175+
if (Array.isArray(data) && data.length > 0) {
176+
this.originalPlayList = data;
177+
return data;
178+
}
179+
return null;
180+
},
181+
// 清除原始播放列表
182+
async clearOriginalPlayList(): Promise<void> {
183+
this.originalPlayList = [];
184+
await musicDB.setItem("originalPlayList", []);
185+
},
160186
// 新增下一首播放歌曲
161187
async setNextPlaySong(song: SongType, index: number): Promise<number> {
162188
// 若为空,则直接添加

src/utils/player.ts

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,17 @@ class Player {
4040
// 初始化媒体会话
4141
this.initMediaSession();
4242
}
43+
/**
44+
* 洗牌数组(Fisher-Yates)
45+
*/
46+
private shuffleArray<T>(arr: T[]): T[] {
47+
const copy = arr.slice();
48+
for (let i = copy.length - 1; i > 0; i--) {
49+
const j = Math.floor(Math.random() * (i + 1));
50+
[copy[i], copy[j]] = [copy[j], copy[i]];
51+
}
52+
return copy;
53+
}
4354
/**
4455
* 重置状态
4556
*/
@@ -667,19 +678,15 @@ class Player {
667678
this.setSeek(0);
668679
await this.play();
669680
}
670-
// 列表循环或处于心动模式
671-
if (playSongMode === "repeat" || playHeartbeatMode || playSong.type === "radio") {
681+
// 列表循环或处于心动模式或随机模式
682+
if (
683+
playSongMode === "repeat" ||
684+
playSongMode === "shuffle" ||
685+
playHeartbeatMode ||
686+
playSong.type === "radio"
687+
) {
672688
statusStore.playIndex += type === "next" ? 1 : -1;
673689
}
674-
// 随机播放
675-
else if (playSongMode === "shuffle") {
676-
let newIndex: number;
677-
// 确保不会随机到同一首
678-
do {
679-
newIndex = Math.floor(Math.random() * playListLength);
680-
} while (newIndex === statusStore.playIndex);
681-
statusStore.playIndex = newIndex;
682-
}
683690
// 单曲循环
684691
else if (playSongMode === "repeat-once") {
685692
statusStore.lyricIndex = -1;
@@ -708,28 +715,65 @@ class Player {
708715
* 切换播放模式
709716
* @param mode 播放模式 repeat / repeat-once / shuffle
710717
*/
711-
togglePlayMode(mode: PlayModeType | false) {
718+
async togglePlayMode(mode: PlayModeType | false) {
712719
const statusStore = useStatusStore();
720+
const dataStore = useDataStore();
721+
const musicStore = useMusicStore();
713722
// 退出心动模式
714723
if (statusStore.playHeartbeatMode) this.toggleHeartMode(false);
715-
// 若传入了指定模式
724+
// 计算目标模式
725+
let targetMode: PlayModeType;
716726
if (mode) {
717-
statusStore.playSongMode = mode;
727+
targetMode = mode;
718728
} else {
719729
switch (statusStore.playSongMode) {
720730
case "repeat":
721-
statusStore.playSongMode = "repeat-once";
731+
targetMode = "repeat-once";
722732
break;
723733
case "shuffle":
724-
statusStore.playSongMode = "repeat";
734+
targetMode = "repeat";
725735
break;
726736
case "repeat-once":
727-
statusStore.playSongMode = "shuffle";
737+
targetMode = "shuffle";
728738
break;
729739
default:
730-
statusStore.playSongMode = "repeat";
740+
targetMode = "repeat";
741+
}
742+
}
743+
// 进入随机模式:保存原顺序并打乱当前歌单
744+
if (targetMode === "shuffle" && statusStore.playSongMode !== "shuffle") {
745+
const currentList = dataStore.playList;
746+
if (currentList && currentList.length > 1) {
747+
const currentSongId = musicStore.playSong?.id;
748+
await dataStore.setOriginalPlayList(currentList);
749+
const shuffled = this.shuffleArray(currentList);
750+
await dataStore.setPlayList(shuffled);
751+
if (currentSongId) {
752+
const newIndex = shuffled.findIndex((s: any) => s?.id === currentSongId);
753+
if (newIndex !== -1) useStatusStore().playIndex = newIndex;
754+
}
755+
}
756+
}
757+
// 离开随机模式:恢复到原顺序
758+
if (
759+
statusStore.playSongMode === "shuffle" &&
760+
(targetMode === "repeat" || targetMode === "repeat-once")
761+
) {
762+
const original = await dataStore.getOriginalPlayList();
763+
if (original && original.length) {
764+
const currentSongId = musicStore.playSong?.id;
765+
await dataStore.setPlayList(original);
766+
if (currentSongId) {
767+
const origIndex = original.findIndex((s: any) => s?.id === currentSongId);
768+
useStatusStore().playIndex = origIndex !== -1 ? origIndex : 0;
769+
} else {
770+
useStatusStore().playIndex = 0;
771+
}
772+
await dataStore.clearOriginalPlayList();
731773
}
732774
}
775+
// 应用模式
776+
statusStore.playSongMode = targetMode;
733777
this.playModeSyncIpc();
734778
}
735779
/**

tsconfig.node.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
"electron/main/utils.ts",
1010
"electron/main/index.d.ts",
1111
"electron/preload/index.d.ts",
12-
"electron/preload/index.ts"
13-
, "dist/lastfm.ts" ],
12+
"electron/preload/index.ts",
13+
"dist/lastfm.ts"
14+
],
1415
"compilerOptions": {
1516
"composite": true,
1617
"types": ["electron-vite/node"]

tsconfig.web.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
"src/**/*",
66
"src/**/*.vue",
77
"electron/main/index.d.ts",
8-
"electron/preload/index.d.ts"
9-
, "dist/lastfm.ts" ],
8+
"electron/preload/index.d.ts",
9+
"dist/lastfm.ts"
10+
],
1011
"compilerOptions": {
1112
"composite": true,
13+
"esModuleInterop": true,
1214
"maxNodeModuleJsDepth": 2,
1315
"baseUrl": ".",
1416
"paths": {

0 commit comments

Comments
 (0)