feat(播放队列): 添加播放队列功能并集成 Pinia 状态管理
新增播放队列功能,使用 Pini a进行状态管理。包括创建播放队列存储、在专辑详情页添加播放功能、以及在播放组件中监听播放状态的变化。同时,更新了依赖以支持 Pinia 的集成。
This commit is contained in:
parent
202e7951f3
commit
94a153ae11
136
package-lock.json
generated
136
package-lock.json
generated
|
@ -10,6 +10,7 @@
|
|||
"dependencies": {
|
||||
"@tailwindcss/vite": "^4.1.7",
|
||||
"axios": "^1.9.0",
|
||||
"pinia": "^3.0.2",
|
||||
"tailwindcss": "^4.1.7",
|
||||
"vue": "^3.5.13",
|
||||
"vue-router": "^4.5.1"
|
||||
|
@ -1354,6 +1355,30 @@
|
|||
"integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vue/devtools-kit": {
|
||||
"version": "7.7.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.6.tgz",
|
||||
"integrity": "sha512-geu7ds7tem2Y7Wz+WgbnbZ6T5eadOvozHZ23Atk/8tksHMFOFylKi1xgGlQlVn0wlkEf4hu+vd5ctj1G4kFtwA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/devtools-shared": "^7.7.6",
|
||||
"birpc": "^2.3.0",
|
||||
"hookable": "^5.5.3",
|
||||
"mitt": "^3.0.1",
|
||||
"perfect-debounce": "^1.0.0",
|
||||
"speakingurl": "^14.0.1",
|
||||
"superjson": "^2.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/devtools-shared": {
|
||||
"version": "7.7.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.6.tgz",
|
||||
"integrity": "sha512-yFEgJZ/WblEsojQQceuyK6FzpFDx4kqrz2ohInxNj5/DnhoX023upTv4OD6lNPLAA5LLkbwPVb10o/7b+Y4FVA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"rfdc": "^1.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/language-core": {
|
||||
"version": "2.2.10",
|
||||
"resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.10.tgz",
|
||||
|
@ -1460,6 +1485,15 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/birpc": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/birpc/-/birpc-2.3.0.tgz",
|
||||
"integrity": "sha512-ijbtkn/F3Pvzb6jHypHRyve2QApOCZDR25D/VnkY2G/lBNcXCTsnsCxgY4k4PkVB7zfwzYbY3O9Lcqe3xufS5g==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
|
@ -1504,6 +1538,21 @@
|
|||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/copy-anything": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz",
|
||||
"integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-what": "^4.1.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.13"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/mesqueeb"
|
||||
}
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
|
@ -1841,6 +1890,24 @@
|
|||
"he": "bin/he"
|
||||
}
|
||||
},
|
||||
"node_modules/hookable": {
|
||||
"version": "5.5.3",
|
||||
"resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
|
||||
"integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/is-what": {
|
||||
"version": "4.1.16",
|
||||
"resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz",
|
||||
"integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.13"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/mesqueeb"
|
||||
}
|
||||
},
|
||||
"node_modules/jiti": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz",
|
||||
|
@ -2154,6 +2221,12 @@
|
|||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/mitt": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
|
||||
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mkdirp": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
|
||||
|
@ -2201,6 +2274,12 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/perfect-debounce": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
|
||||
"integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
|
@ -2219,6 +2298,36 @@
|
|||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/pinia": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.2.tgz",
|
||||
"integrity": "sha512-sH2JK3wNY809JOeiiURUR0wehJ9/gd9qFN2Y828jCbxEzKEmEt0pzCXwqiSTfuRsK9vQsOflSdnbdBOGrhtn+g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/devtools-api": "^7.7.2"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/posva"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.4.4",
|
||||
"vue": "^2.7.0 || ^3.5.11"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/pinia/node_modules/@vue/devtools-api": {
|
||||
"version": "7.7.6",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.6.tgz",
|
||||
"integrity": "sha512-b2Xx0KvXZObePpXPYHvBRRJLDQn5nhKjXh7vUhMEtWxz1AYNFOVIsh5+HLP8xDGL7sy+Q7hXeUxPHB/KgbtsPw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/devtools-kit": "^7.7.6"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.3",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
|
||||
|
@ -2253,6 +2362,12 @@
|
|||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/rfdc": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
|
||||
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.41.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.0.tgz",
|
||||
|
@ -2301,6 +2416,27 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/speakingurl": {
|
||||
"version": "14.0.1",
|
||||
"resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz",
|
||||
"integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==",
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/superjson": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz",
|
||||
"integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"copy-anything": "^3.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "4.1.7",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.7.tgz",
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
"dependencies": {
|
||||
"@tailwindcss/vite": "^4.1.7",
|
||||
"axios": "^1.9.0",
|
||||
"pinia": "^3.0.2",
|
||||
"tailwindcss": "^4.1.7",
|
||||
"vue": "^3.5.13",
|
||||
"vue-router": "^4.5.1"
|
||||
|
|
|
@ -1,3 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import { usePlayQueueStore } from '../stores/usePlayQueueStore'
|
||||
import { watch } from 'vue'
|
||||
|
||||
const playQueue = usePlayQueueStore()
|
||||
|
||||
watch(() => playQueue.isPlaying, (newValue) => {
|
||||
console.log(newValue)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="bg-[#070909a7] backdrop-blur-3xl h-24 shadow-[0px_-1px_1rem_0px_rgba(0,0,0,0.1)] border-t border-t-[#1c1c1c] sticky bottom-0 w-full">
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { createApp } from 'vue'
|
||||
import { createWebHashHistory, createRouter } from 'vue-router'
|
||||
import './style.css'
|
||||
import { createPinia } from 'pinia'
|
||||
|
||||
import App from './App.vue'
|
||||
import HomePage from './pages/Home.vue'
|
||||
import AlbumDetailView from './pages/AlbumDetail.vue'
|
||||
|
@ -15,4 +17,7 @@ const router = createRouter({
|
|||
routes
|
||||
})
|
||||
|
||||
; createApp(App).use(router).mount('#app')
|
||||
const pinia = createPinia()
|
||||
|
||||
createApp(App).use(router).use(pinia).mount('#app')
|
||||
|
||||
|
|
|
@ -2,17 +2,19 @@
|
|||
import { ref, onMounted } from 'vue'
|
||||
import apis from '../apis'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { usePlayQueueStore } from '../stores/usePlayQueueStore'
|
||||
|
||||
const album = ref<Album>()
|
||||
|
||||
const route = useRoute()
|
||||
const albumId = route.params.albumId
|
||||
|
||||
const playQueue = usePlayQueueStore()
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const res = await apis.getAlbum(albumId as string)
|
||||
album.value = res
|
||||
console.log(res)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
|
@ -24,6 +26,24 @@ function artistsOrganize(list: string[]) {
|
|||
return artist
|
||||
}).join(' / ')
|
||||
}
|
||||
|
||||
function playTheAlbum() {
|
||||
if (playQueue.queueReplaceLock) {
|
||||
if (!confirm("当前操作会将你的待播列表清空、放入这张专辑所有曲目,并从新待播清单的开头播放。继续吗?")) { return }
|
||||
playQueue.queueReplaceLock = false
|
||||
}
|
||||
|
||||
let newPlayQueue = []
|
||||
for (const track of album.value?.songs ?? []) {
|
||||
newPlayQueue.push({
|
||||
song: track,
|
||||
album: album.value
|
||||
})
|
||||
}
|
||||
playQueue.list = newPlayQueue
|
||||
playQueue.currentIndex = 0
|
||||
playQueue.isPlaying = true
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -46,7 +66,9 @@ function artistsOrganize(list: string[]) {
|
|||
<div class="flex justify-between items-center">
|
||||
<div class="flex gap-2">
|
||||
<button
|
||||
class="bg-sky-500/20 hover:bg-sky-500/30 active:bg-sky-600/30 active:shadow-inner border border-[#ffffff39] rounded-full w-56 h-10 text-base text-white flex justify-center items-center gap-2">
|
||||
class="bg-sky-500/20 hover:bg-sky-500/30 active:bg-sky-600/30 active:shadow-inner border border-[#ffffff39] rounded-full w-56 h-10 text-base text-white flex justify-center items-center gap-2"
|
||||
@click="playTheAlbum"
|
||||
>
|
||||
<div class="w-4 h-4">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path
|
||||
|
|
11
src/stores/usePlayQueueStore.ts
Normal file
11
src/stores/usePlayQueueStore.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { defineStore } from "pinia"
|
||||
import { ref } from "vue"
|
||||
|
||||
export const usePlayQueueStore = defineStore('queue', () =>{
|
||||
const list = ref<QueueItem[]>([])
|
||||
const currentIndex = ref<number>(0)
|
||||
const isPlaying = ref<boolean>(false)
|
||||
const queueReplaceLock = ref<boolean>(false)
|
||||
|
||||
return { list, currentIndex, isPlaying, queueReplaceLock }
|
||||
})
|
5
src/vite-env.d.ts
vendored
5
src/vite-env.d.ts
vendored
|
@ -33,3 +33,8 @@ interface ApiResponse {
|
|||
msg: string
|
||||
data: unknown
|
||||
}
|
||||
|
||||
interface QueueItem {
|
||||
song: Song
|
||||
album?: Album
|
||||
}
|
Loading…
Reference in New Issue
Block a user