mirror of
https://github.com/imsyy/SPlayer.git
synced 2025-11-26 03:44:57 +08:00
✨ feat: 优化随机播放问题 & 播放页字体抖动效果优化
This commit is contained in:
@@ -324,6 +324,7 @@ onBeforeUnmount(() => {
|
||||
padding: 10px 16px;
|
||||
transform: scale(0.86);
|
||||
transform-origin: left center;
|
||||
will-change: filter, opacity, transform;
|
||||
transition:
|
||||
filter 0.35s,
|
||||
opacity 0.35s,
|
||||
|
||||
@@ -15,6 +15,7 @@ import { formatCategoryList } from "@/utils/format";
|
||||
|
||||
interface ListState {
|
||||
playList: SongType[];
|
||||
originalPlayList: SongType[];
|
||||
historyList: SongType[];
|
||||
cloudPlayList: SongType[];
|
||||
searchHistory: string[];
|
||||
@@ -54,6 +55,8 @@ export const useDataStore = defineStore("data", {
|
||||
state: (): ListState => ({
|
||||
// 播放列表
|
||||
playList: [],
|
||||
// 原始播放列表
|
||||
originalPlayList: [],
|
||||
// 播放历史
|
||||
historyList: [],
|
||||
// 搜索历史
|
||||
@@ -157,6 +160,29 @@ export const useDataStore = defineStore("data", {
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
// 保存原始播放列表
|
||||
async setOriginalPlayList(data: SongType[]): Promise<void> {
|
||||
const snapshot = cloneDeep(data);
|
||||
this.originalPlayList = snapshot;
|
||||
await musicDB.setItem("originalPlayList", snapshot);
|
||||
},
|
||||
// 获取原始播放列表
|
||||
async getOriginalPlayList(): Promise<SongType[] | null> {
|
||||
if (Array.isArray(this.originalPlayList) && this.originalPlayList.length > 0) {
|
||||
return this.originalPlayList;
|
||||
}
|
||||
const data = (await musicDB.getItem("originalPlayList")) as SongType[] | null;
|
||||
if (Array.isArray(data) && data.length > 0) {
|
||||
this.originalPlayList = data;
|
||||
return data;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// 清除原始播放列表
|
||||
async clearOriginalPlayList(): Promise<void> {
|
||||
this.originalPlayList = [];
|
||||
await musicDB.setItem("originalPlayList", []);
|
||||
},
|
||||
// 新增下一首播放歌曲
|
||||
async setNextPlaySong(song: SongType, index: number): Promise<number> {
|
||||
// 若为空,则直接添加
|
||||
|
||||
@@ -40,6 +40,17 @@ class Player {
|
||||
// 初始化媒体会话
|
||||
this.initMediaSession();
|
||||
}
|
||||
/**
|
||||
* 洗牌数组(Fisher-Yates)
|
||||
*/
|
||||
private shuffleArray<T>(arr: T[]): T[] {
|
||||
const copy = arr.slice();
|
||||
for (let i = copy.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[copy[i], copy[j]] = [copy[j], copy[i]];
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
/**
|
||||
* 重置状态
|
||||
*/
|
||||
@@ -667,19 +678,15 @@ class Player {
|
||||
this.setSeek(0);
|
||||
await this.play();
|
||||
}
|
||||
// 列表循环或处于心动模式
|
||||
if (playSongMode === "repeat" || playHeartbeatMode || playSong.type === "radio") {
|
||||
// 列表循环或处于心动模式或随机模式
|
||||
if (
|
||||
playSongMode === "repeat" ||
|
||||
playSongMode === "shuffle" ||
|
||||
playHeartbeatMode ||
|
||||
playSong.type === "radio"
|
||||
) {
|
||||
statusStore.playIndex += type === "next" ? 1 : -1;
|
||||
}
|
||||
// 随机播放
|
||||
else if (playSongMode === "shuffle") {
|
||||
let newIndex: number;
|
||||
// 确保不会随机到同一首
|
||||
do {
|
||||
newIndex = Math.floor(Math.random() * playListLength);
|
||||
} while (newIndex === statusStore.playIndex);
|
||||
statusStore.playIndex = newIndex;
|
||||
}
|
||||
// 单曲循环
|
||||
else if (playSongMode === "repeat-once") {
|
||||
statusStore.lyricIndex = -1;
|
||||
@@ -708,28 +715,65 @@ class Player {
|
||||
* 切换播放模式
|
||||
* @param mode 播放模式 repeat / repeat-once / shuffle
|
||||
*/
|
||||
togglePlayMode(mode: PlayModeType | false) {
|
||||
async togglePlayMode(mode: PlayModeType | false) {
|
||||
const statusStore = useStatusStore();
|
||||
const dataStore = useDataStore();
|
||||
const musicStore = useMusicStore();
|
||||
// 退出心动模式
|
||||
if (statusStore.playHeartbeatMode) this.toggleHeartMode(false);
|
||||
// 若传入了指定模式
|
||||
// 计算目标模式
|
||||
let targetMode: PlayModeType;
|
||||
if (mode) {
|
||||
statusStore.playSongMode = mode;
|
||||
targetMode = mode;
|
||||
} else {
|
||||
switch (statusStore.playSongMode) {
|
||||
case "repeat":
|
||||
statusStore.playSongMode = "repeat-once";
|
||||
targetMode = "repeat-once";
|
||||
break;
|
||||
case "shuffle":
|
||||
statusStore.playSongMode = "repeat";
|
||||
targetMode = "repeat";
|
||||
break;
|
||||
case "repeat-once":
|
||||
statusStore.playSongMode = "shuffle";
|
||||
targetMode = "shuffle";
|
||||
break;
|
||||
default:
|
||||
statusStore.playSongMode = "repeat";
|
||||
targetMode = "repeat";
|
||||
}
|
||||
}
|
||||
// 进入随机模式:保存原顺序并打乱当前歌单
|
||||
if (targetMode === "shuffle" && statusStore.playSongMode !== "shuffle") {
|
||||
const currentList = dataStore.playList;
|
||||
if (currentList && currentList.length > 1) {
|
||||
const currentSongId = musicStore.playSong?.id;
|
||||
await dataStore.setOriginalPlayList(currentList);
|
||||
const shuffled = this.shuffleArray(currentList);
|
||||
await dataStore.setPlayList(shuffled);
|
||||
if (currentSongId) {
|
||||
const newIndex = shuffled.findIndex((s: any) => s?.id === currentSongId);
|
||||
if (newIndex !== -1) useStatusStore().playIndex = newIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 离开随机模式:恢复到原顺序
|
||||
if (
|
||||
statusStore.playSongMode === "shuffle" &&
|
||||
(targetMode === "repeat" || targetMode === "repeat-once")
|
||||
) {
|
||||
const original = await dataStore.getOriginalPlayList();
|
||||
if (original && original.length) {
|
||||
const currentSongId = musicStore.playSong?.id;
|
||||
await dataStore.setPlayList(original);
|
||||
if (currentSongId) {
|
||||
const origIndex = original.findIndex((s: any) => s?.id === currentSongId);
|
||||
useStatusStore().playIndex = origIndex !== -1 ? origIndex : 0;
|
||||
} else {
|
||||
useStatusStore().playIndex = 0;
|
||||
}
|
||||
await dataStore.clearOriginalPlayList();
|
||||
}
|
||||
}
|
||||
// 应用模式
|
||||
statusStore.playSongMode = targetMode;
|
||||
this.playModeSyncIpc();
|
||||
}
|
||||
/**
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
"electron/main/utils.ts",
|
||||
"electron/main/index.d.ts",
|
||||
"electron/preload/index.d.ts",
|
||||
"electron/preload/index.ts"
|
||||
, "dist/lastfm.ts" ],
|
||||
"electron/preload/index.ts",
|
||||
"dist/lastfm.ts"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"types": ["electron-vite/node"]
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
"src/**/*",
|
||||
"src/**/*.vue",
|
||||
"electron/main/index.d.ts",
|
||||
"electron/preload/index.d.ts"
|
||||
, "dist/lastfm.ts" ],
|
||||
"electron/preload/index.d.ts",
|
||||
"dist/lastfm.ts"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"esModuleInterop": true,
|
||||
"maxNodeModuleJsDepth": 2,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
|
||||
Reference in New Issue
Block a user