重开一个组件再写当前播放完成

This commit is contained in:
zilong 2021-10-24 20:10:59 +08:00
parent 6a257b9c65
commit 9c7b484b36
9 changed files with 213 additions and 96 deletions

View File

@ -215,7 +215,7 @@ body {
bottom: 64px; bottom: 64px;
// left: 0; // left: 0;
width: 500px; width: 500px;
background-color: #f6f6f6; background-color: #fff;
z-index: 1000; z-index: 1000;
border: #ddd solid 1px; border: #ddd solid 1px;
// border-top-left-radius: 8px; // border-top-left-radius: 8px;

1
src/assets/svgs/Dots.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="5" cy="12" r="1"></circle><circle cx="12" cy="12" r="1"></circle><circle cx="19" cy="12" r="1"></circle></g></svg>

After

Width:  |  Height:  |  Size: 330 B

View File

@ -1,10 +1,20 @@
<script setup> <script setup>
import { ref, defineProps, onUnmounted, onDeactivated } from "vue";
import { useRouter } from "vue-router";
const props = defineProps({ artists: Array, onLeave: Function });
const router = useRouter()
// console.log(props.artists);
const click = (id) => {
props.onLeave?.()
router.push('/singer/' + id)
}
</script> </script>
<template> <template>
<template v-for="(ar, idx) of artists" key="idx"> <template v-for="(ar, idx) of artists" key="idx">
<span <span
@click="$router.push('/singer/' + ar.id)" @click="click(ar.id)"
style="margin-right: 4px; cursor: pointer" style="margin-right: 4px; cursor: pointer"
>{{ ar.name }}</span >{{ ar.name }}</span
> >
@ -12,9 +22,9 @@
</template> </template>
<script> <script>
export default { // export default {
props: ["artists"], // props: ["artists"],
}; // };
</script> </script>
<style></style> <style></style>

View File

@ -2,8 +2,8 @@ import { createStore, storeKey } from "vuex";
export default createStore({ export default createStore({
state: { state: {
appVersion: "0.0.1", // appVersion: "0.0.1",
debugStr: "测试debug字符", // debugStr: "测试debug字符",
settings: { settings: {
currentRoute: "/discover/recommend", //当前路由 currentRoute: "/discover/recommend", //当前路由
songId: 0, //歌曲id songId: 0, //歌曲id
@ -11,8 +11,9 @@ export default createStore({
playMode: 0, //播放模式0-3顺序循环单曲随机。 playMode: 0, //播放模式0-3顺序循环单曲随机。
lastPlayed: [], //最近播放 lastPlayed: [], //最近播放
playingList: [], //当前播放 playingList: [], //当前播放
tArr: [], //测试数组
ts: "", //测试字符
}, },
haha: 'haha',
caches: {}, caches: {},
theme: { theme: {
//主题覆盖变量 //主题覆盖变量
@ -32,9 +33,7 @@ export default createStore({
//根据当前路由计算主菜单的选择项 //根据当前路由计算主菜单的选择项
mainMenuSelected: (state) => (menuOptions) => { mainMenuSelected: (state) => (menuOptions) => {
return menuOptions.find((item) => { return menuOptions.find((item) => {
return ( return state.settings.currentRoute.indexOf(item.key) > -1;
state.settings.currentRoute.indexOf(item.key) > -1
);
})?.key; })?.key;
}, },
cache: cache:
@ -44,8 +43,7 @@ export default createStore({
if ( if (
state.caches[key].time && state.caches[key].time &&
(expire <= 0 || (expire <= 0 ||
Date.now() - state.caches[key].time < Date.now() - state.caches[key].time < 1000 * expire)
1000 * expire)
) )
return state.caches[key].data; return state.caches[key].data;
} }
@ -56,7 +54,7 @@ export default createStore({
//载入settings设置 //载入settings设置
loadSettings(state) { loadSettings(state) {
const l = localStorage.getItem("zmusic.settings"); const l = localStorage.getItem("zmusic.settings");
if (l) state.settings ={...state.settings, ...JSON.parse(l)}; if (l) state.settings = { ...state.settings, ...JSON.parse(l) };
}, },
//保存settings设置 //保存settings设置
saveSettings(state, settings) { saveSettings(state, settings) {
@ -67,7 +65,7 @@ export default createStore({
//载入caches设置 //载入caches设置
loadCaches(state) { loadCaches(state) {
const l = localStorage.getItem("zmusic.caches"); const l = localStorage.getItem("zmusic.caches");
if (l) state.caches = {...state.caches, ...JSON.parse(l)} if (l) state.caches = { ...state.caches, ...JSON.parse(l) };
}, },
//保存caches设置 //保存caches设置
saveCaches(state, caches) { saveCaches(state, caches) {
@ -84,7 +82,7 @@ export default createStore({
//载入theme设置 //载入theme设置
loadTheme(state) { loadTheme(state) {
const l = localStorage.getItem("zmusic.theme"); const l = localStorage.getItem("zmusic.theme");
if (l) state.theme = {...state.theme, ...JSON.parse(l)}; if (l) state.theme = { ...state.theme, ...JSON.parse(l) };
}, },
//保存theme设置 //保存theme设置
saveTheme(state, theme) { saveTheme(state, theme) {
@ -111,7 +109,18 @@ export default createStore({
}); });
if (!f) { if (!f) {
// console.log("add to playingList"); // console.log("add to playingList");
state.settings.playingList.unshift(song) state.settings.playingList.unshift(song);
saveLoaclSettings(state.settings);
}
},
removePlayingList(state, song) {
// console.log('removePlayingList', song)
let idx = state.settings.playingList.findIndex(
(item) => item.id === song.id
);
// console.log(idx)
if (idx > -1) {
state.settings.playingList.splice(idx, 1);
saveLoaclSettings(state.settings); saveLoaclSettings(state.settings);
} }
}, },
@ -121,10 +130,7 @@ export default createStore({
}); });
function saveLoaclSettings(s) { function saveLoaclSettings(s) {
localStorage.setItem( localStorage.setItem("zmusic.settings", JSON.stringify(s));
"zmusic.settings",
JSON.stringify(s)
);
} }
function saveLoaclCaches(s) { function saveLoaclCaches(s) {
localStorage.setItem("zmusic.caches", JSON.stringify(s)); localStorage.setItem("zmusic.caches", JSON.stringify(s));

View File

@ -75,7 +75,7 @@ const playNext = async (step) => {
case 3: // case 3: //
if (playingList.length <= 1) return; // if (playingList.length <= 1) return; //
const i = Math.floor(Math.random() * (playingList.length - 1)); const i = Math.floor(Math.random() * (playingList.length - 1));
if (i >= idx) idx = i+1; if (i >= idx) idx = i + 1;
else idx = i; else idx = i;
break; break;
} }
@ -90,6 +90,18 @@ const forward = async () => {
playNext(1); playNext(1);
}; };
const stop = async () => {
pause();
if (store.state.settings.playingList.length < 1) {
audioEl.value.src = "";
lastPause = 0;
store.commit("saveSettings", {
songId: null,
});
pubsub.publish('zp.hideSongInfo')
}
};
const play = async (id, im = true) => { const play = async (id, im = true) => {
console.log(id); console.log(id);
await getSongUrl(id) await getSongUrl(id)
@ -177,6 +189,12 @@ const psToken = pubsub.subscribe("zp", (msg, data) => {
case "zp.play": case "zp.play":
play(data.id, data.im); play(data.id, data.im);
break; break;
case "zp.next":
forward();
break;
case "zp.stop":
stop();
break;
case "zp.setProgressScale": case "zp.setProgressScale":
setProgressScale(data.scale); setProgressScale(data.scale);
break; break;
@ -249,13 +267,13 @@ onUnmounted(() => {
</n-icon> </n-icon>
</template> </template>
</n-button> </n-button>
<n-button circle> <!-- <n-button circle>
<template #icon> <template #icon>
<n-icon> <n-icon>
<TrashOutline /> <TrashOutline />
</n-icon> </n-icon>
</template> </template>
</n-button> </n-button> -->
</n-space> </n-space>
<!-- </div> --> <!-- </div> -->

View File

@ -20,7 +20,7 @@ const store = useStore()
const showInfo = ref(false); const showInfo = ref(false);
const info = reactive({ const info = reactive({
name: "", name: "",
artists: "", artists: [],
album: {}, album: {},
duration: 0, duration: 0,
mv: 0, mv: 0,
@ -44,7 +44,6 @@ const songInfo = (id, im) => {
date: Date.now(), date: Date.now(),
}, ...toRaw(info)} }, ...toRaw(info)}
store.commit('savePlayed', p) store.commit('savePlayed', p)
store.commit('addToPlayingList', p) store.commit('addToPlayingList', p)
console.log('savePlayed'); console.log('savePlayed');
} }
@ -67,6 +66,9 @@ const psToken = pubsub.subscribe("zp", (msg, data) => {
case "zp.getSongInfo": case "zp.getSongInfo":
songInfo(data.id, data.im); songInfo(data.id, data.im);
break; break;
case "zp.hideSongInfo":
showInfo.value = false
break;
case "zp.progress": case "zp.progress":
totalTime.value = zpTime(data.total * 1000) totalTime.value = zpTime(data.total * 1000)
currTime.value = zpTime(data.progress * 1000) currTime.value = zpTime(data.progress * 1000)

View File

@ -16,6 +16,7 @@ import {
NButtonGroup, NButtonGroup,
NSpace, NSpace,
NIcon, NIcon,
NDropdown,
NMenu, NMenu,
NLayout, NLayout,
NLayoutHeader, NLayoutHeader,
@ -28,11 +29,12 @@ import {
} from "naive-ui"; } from "naive-ui";
import Play from "@/assets/svgs/Play_.svg"; import Play from "@/assets/svgs/Play_.svg";
import Pause from "@/assets/svgs/Pause.svg"; import Pause from "@/assets/svgs/Pause.svg";
import svgDots from "@/assets/svgs/Dots.svg";
import dayjs from "dayjs"; import dayjs from "dayjs";
import "dayjs/locale/zh-cn"; import "dayjs/locale/zh-cn";
import duration from "dayjs/plugin/duration"; import duration from "dayjs/plugin/duration";
import pubsub from "pubsub-js"; import pubsub from "pubsub-js";
import ArtistsSpan from '@/components/ArtistsSpan.vue'; import ArtistsSpan from "@/components/ArtistsSpan.vue";
const store = useStore(); const store = useStore();
const router = useRouter(); const router = useRouter();
@ -41,8 +43,6 @@ const playingList = ref([]);
const wpTable = ref(""); const wpTable = ref("");
const listHeight = ref(0); const listHeight = ref(0);
// playingList.value = toRaw(store.state.settings.playingList);
const token = pubsub.subscribe("zp", (msg, data) => { const token = pubsub.subscribe("zp", (msg, data) => {
switch (msg) { switch (msg) {
case "zp.togglePlaying": case "zp.togglePlaying":
@ -66,86 +66,143 @@ watch(
} }
); );
let dragIdx = -1 let dragIdx = -1;
const dragstart = (idx) => { const dragstart = (idx) => {
// console.log('start ',idx); // console.log('start ',idx);
dragIdx=idx dragIdx = idx;
} };
const dragenter = (e, idx) => { const dragenter = (e, idx) => {
// console.log('enter ',idx); // console.log('enter ',idx);
e.preventDefault(); e.preventDefault();
if(dragIdx !== idx){ if (dragIdx !== idx) {
let dragItem = toRaw(playingList.value)[dragIdx] let dragItem = toRaw(playingList.value)[dragIdx];
let item = toRaw(playingList.value)[idx] let item = toRaw(playingList.value)[idx];
// console.log(playingList,dragItem); // console.log(playingList,dragItem);
playingList.value.splice(dragIdx,1) playingList.value.splice(dragIdx, 1);
playingList.value.splice(idx, 0, dragItem) playingList.value.splice(idx, 0, dragItem);
dragIdx=idx dragIdx = idx;
store.commit('saveSettings', { store.commit("saveSettings", {
playingList: playingList.value playingList: playingList.value,
}) });
} }
};
}
const dragover = (e, idx) => { const dragover = (e, idx) => {
// console.log('over ',idx); // console.log('over ',idx);
e.preventDefault(); e.preventDefault();
} };
const drop = (e, idx) => { const drop = (e, idx) => {
// console.log('drop ',idx); // console.log('drop ',idx);
e.preventDefault(); e.preventDefault();
};
//
const options = [
{
label: "播放",
key: "play",
},
// {
// label: "",
// key: "nextToPlay",
// },
{
type: 'divider',
key: ''
},
{
label: "从列表删除",
key: "remove",
},
];
//
const handleSelect = (key, id) => {
switch(key){
case 'play':
pubsub.publish('zp.play',{
id, im: true,
})
break;
case 'nextToPlay':
break;
case 'remove':
store.commit('removePlayingList', {id})
if(playingList.value.length>0)
pubsub.publish('zp.next')
else
pubsub.publish('zp.stop')
break;
}
};
const handleClick = () => {
// showDropdownRef.value = !showDropdownRef.value;
};
const arLeave = ()=>{
pubsub.publish('zp.togglePlaying',)
} }
</script> </script>
<template> <template>
<!-- <n-layout>
<n-layout-header
style="padding: 10px 12px 0px 12px; font-size: 24px"
>当前播放
</n-layout-header>
<n-layout has-sider>
<n-layout-content style="padding: 6px 12px; font-size: 12px">
{{ playingList.length }}
</n-layout-content>
<n-layout-sider width="100" style="padding: 0 12px 6px 12px">
<n-button size="tiny">清除列表</n-button>
</n-layout-sider>
</n-layout>
</n-layout> -->
<div class="title">当前播放</div> <div class="title">当前播放</div>
<div class="tools"> <div class="tools">
<div class="count">{{ playingList.length }}</div> <div class="count">{{ playingList.length }}</div>
<div class="btns"><n-button size="tiny">清除列表</n-button></div> <div class="btns"><n-button size="tiny">清除列表</n-button></div>
</div> </div>
<div class="wp-list" ref="wpTable"> <div class="wp-list" ref="wpTable">
<div class="tr" v-for="(p, idx) in playingList" :key="idx" <div
draggable="true" class="tr"
@dragstart="dragstart(idx)" v-for="(p, idx) in playingList"
@dragenter="dragenter($event, idx)" :key="idx"
@dragover="dragover($event, idx)" draggable="true"
@drop="drop($event, idx)" @dragstart="dragstart(idx)"
> @dragenter="dragenter($event, idx)"
@dragover="dragover($event, idx)"
@drop="drop($event, idx)"
@dblclick="pubsub.publish('zp.play', {id: p.id,im: true})"
>
<div class="icon"> <div class="icon">
<NButton <NButton
v-show="p.id === store.state.settings.songId" v-show="p.id === store.state.settings.songId"
text text
type="primary" type="primary"
circle
size="tiny" size="tiny"
> >
<NIcon style="bottom: -1px;left:-2px;position: absolute;"> <NIcon style="bottom: -1px; left: -2px; position: absolute">
<Play v-if="store.state.settings.playing"></Play> <Play v-if="store.state.settings.playing"></Play>
<Pause v-else></Pause> <Pause v-else></Pause>
</NIcon> </NIcon>
</NButton> </NButton>
</div> </div>
<div class="name">{{ p.name }}</div> <div class="name">
<div class="ar"> <span class="ntext">{{ p.name }}</span>
<ArtistsSpan :artists="p.artists" /> <span class="nm">
<n-dropdown
placement="right-start"
@select="handleSelect($event, p.id)"
trigger="click"
:options="options"
:show-arrow="true"
>
<NButton
class="mn"
text
type="primary"
style="font-size: 20px"
>
<NIcon>
<svg-dots />
</NIcon>
</NButton>
</n-dropdown>
</span>
</div> </div>
<div class="al">{{p.album.name}}</div> <div class="ar">
<ArtistsSpan :artists="p.artists" :onLeave="arLeave"/>
</div>
<div class="al">{{ p.album.name }}</div>
<div class="dt"> <div class="dt">
{{dayjs.duration(p.duration).format("mm:ss")}} {{ dayjs.duration(p.duration).format("mm:ss") }}
</div> </div>
</div> </div>
</div> </div>
@ -163,10 +220,10 @@ export default {};
} }
.tools { .tools {
display: flex; display: flex;
align-content: center; align-items: center;
.count { .count {
flex: 1; flex: 1;
padding: 2px 24px; padding: 6px 24px;
font-size: 12px; font-size: 12px;
} }
.btns { .btns {
@ -176,42 +233,64 @@ export default {};
.wp-list { .wp-list {
position: absolute; position: absolute;
bottom: 0px; bottom: 0px;
top: 76px; top: 80px;
right: 0; right: 0;
left: 0; left: 0;
overflow-y: auto; overflow-y: auto;
.tr{ .tr {
display: flex; display: flex;
font-size: 14px; font-size: 14px;
border-top: 1px #ddd solid; border-top: 1px #eee solid;
border-bottom: 1px #ddd solid; border-bottom: 1px #eee solid;
margin-bottom: -1px; margin-bottom: -1px;
>*{ > * {
padding: 4px 6px; padding: 4px 6px;
} }
.icon{ &:nth-child(2n + 1) {
background-color: #f6f6f6;
}
&:hover {
background-color: #eee;
.name .mn {
display: block;
}
}
.icon {
padding-left: 10px; padding-left: 10px;
width: 20px; width: 20px;
} }
.name{ .name {
flex: 1; flex: 1;
.text-el-line-normal() .text-el-line-normal();
display: flex;
align-items: center;
.ntext {
.text-el-line-normal();
}
.mn {
flex: 1;
display: none;
}
} }
.ar{ .ar {
width: 120px; width: 120px;
.text-el-line-normal() .text-el-line-normal();
} }
.al{ .al {
width: 100px; width: 80px;
margin-top: 1px; margin-top: 1px;
color: #999; color: #999;
font-size: 12px; font-size: 12px;
.text-el-line-normal() .text-el-line-normal();
} }
.dt{ .dt {
margin-top: 1px; margin-top: 1px;
color: #999; color: #999;
font-size: 12px; font-size: 12px;

View File

@ -121,9 +121,9 @@ const route = useRoute();
<!-- <NScrollbar > --> <!-- <NScrollbar > -->
<div class="ld-width"> <div class="ld-width">
<router-view v-slot="{ Component }"> <router-view v-slot="{ Component }">
<keep-alive> <!-- <keep-alive exclude="Recommend"> -->
<component :is="Component" /> <component :is="Component" />
</keep-alive> <!-- </keep-alive> -->
</router-view> </router-view>
<!-- <keep-alive> <!-- <keep-alive>
<router-view></router-view> <router-view></router-view>

View File

@ -217,10 +217,10 @@ import {
import pubsub from "pubsub-js"; import pubsub from "pubsub-js";
import ArtistsSpan from "@/components/ArtistsSpan.vue"; import ArtistsSpan from "@/components/ArtistsSpan.vue";
console.log("recommend 初始化"); // console.log("recommend ");
onUnmounted(() => { // onUnmounted(() => {
console.log('recommend 卸载'); // console.log('recommend ');
}) // })
const store = useStore(); const store = useStore();
const play = (id) => { const play = (id) => {
@ -237,7 +237,7 @@ getBanner(0)
banners: { data: banners.value, time: Date.now() }, banners: { data: banners.value, time: Date.now() },
}); });
// console.log(banners.value); // console.log(banners.value);
console.log("recommend 轮播图片初始化"); // console.log("recommend ");
}) })
.catch((err) => { .catch((err) => {
console.log("getBanner err", err); console.log("getBanner err", err);
@ -323,6 +323,7 @@ getPersonalizedMV()
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@import "@/assets/css/common.less"; @import "@/assets/css/common.less";
.wp-carousel { .wp-carousel {