dev...
This commit is contained in:
177
src/views/common/SongDetail.vue
Normal file
177
src/views/common/SongDetail.vue
Normal file
@@ -0,0 +1,177 @@
|
||||
<script setup>
|
||||
import { ref, onUnmounted, watch } from "vue";
|
||||
import { NButton, NIcon } from "naive-ui";
|
||||
import { useStore } from "vuex";
|
||||
import svgChevrongDown from "@/assets/svgs/ChevronDown.svg";
|
||||
import pubsub from "pubsub-js";
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const songInfo = ref(null);
|
||||
const lyric = ref(null);
|
||||
const coverAngle = ref(0);
|
||||
|
||||
let interval;
|
||||
watch(
|
||||
() => store.state.settings.playing,
|
||||
(val) => {
|
||||
if(val){
|
||||
interval = setInterval(() => {
|
||||
coverAngle.value += .5
|
||||
}, 100);
|
||||
} else {
|
||||
clearInterval(interval)
|
||||
}
|
||||
|
||||
},
|
||||
{immediate: true}
|
||||
);
|
||||
|
||||
//#region 处理消息订阅
|
||||
|
||||
const token = pubsub.subscribe("zp", (msg, data) => {
|
||||
switch (msg) {
|
||||
case "zp.songInfo":
|
||||
console.log("SongDetail: 收到歌曲详细信息。", data);
|
||||
songInfo.value = data;
|
||||
break;
|
||||
case "zp.lyric":
|
||||
lyric.value = data;
|
||||
break;
|
||||
}
|
||||
});
|
||||
//卸载组件
|
||||
onUnmounted(() => {
|
||||
pubsub.unsubscribe(token);
|
||||
});
|
||||
//#endregion
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="sdTitle">
|
||||
<n-button
|
||||
circle
|
||||
size="small"
|
||||
@click="pubsub.publish('zp.toggleSongDetail')"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<svgChevrongDown />
|
||||
</n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
</div>
|
||||
<div id="sdContent" v-if="songInfo">
|
||||
<div class="detail">
|
||||
<div class="disk">
|
||||
<div class="styli">
|
||||
<img
|
||||
src="@/assets/images/needle.png"
|
||||
:class="{ playing: store.state.settings.playing }"
|
||||
/>
|
||||
</div>
|
||||
<div class="bg">
|
||||
<img class="disk" src="@/assets/images/disk.png" />
|
||||
<img
|
||||
class="cover"
|
||||
:src="songInfo.album.picUrl"
|
||||
:style="{ transform: 'rotateZ(' + coverAngle + 'deg)' }"
|
||||
/>
|
||||
</div>
|
||||
<div class="pic"></div>
|
||||
</div>
|
||||
<div class="song">
|
||||
歌曲
|
||||
<div class="name"></div>
|
||||
<div class="others"></div>
|
||||
<div class="ly"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="comments"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
#sdTitle {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 280px;
|
||||
height: 40px;
|
||||
background-color: #f9f9f9;
|
||||
padding-left: 50px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
#sdContent {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 40px;
|
||||
right: 0;
|
||||
bottom: 64px;
|
||||
background-color: #f6f6f6;
|
||||
|
||||
.styli {
|
||||
position: relative;
|
||||
height: 60px;
|
||||
img {
|
||||
width: 160px;
|
||||
position: absolute;
|
||||
left: 135px;
|
||||
transform-origin: 13px 13px;
|
||||
z-index: 100;
|
||||
}
|
||||
.playing {
|
||||
transform: rotateZ(28deg);
|
||||
}
|
||||
}
|
||||
.detail {
|
||||
// margin: 2em;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
.pointer {
|
||||
height: 50px;
|
||||
}
|
||||
.disk {
|
||||
--back-color: #eee;
|
||||
--width-num: 340;
|
||||
--padding-num: 10;
|
||||
--width: calc(var(--width-num) * 1px);
|
||||
--height: calc(var(--width-num) * 1px);
|
||||
|
||||
// position: relative;
|
||||
// width: 300px;
|
||||
.bg {
|
||||
position: relative;
|
||||
|
||||
width: var(--width);
|
||||
height: var(--height);
|
||||
background-color: var(--back-color);
|
||||
border-radius: var(--width);
|
||||
padding: calc(var(--padding-num) * 1px);
|
||||
img.disk {
|
||||
width: calc(
|
||||
(var(--width-num) - var(--padding-num) * 2) * 1px
|
||||
);
|
||||
}
|
||||
img.cover {
|
||||
width: 220px;
|
||||
border-radius: 200px;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
left: 62px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.song {
|
||||
position: relative;
|
||||
width: 400px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -7,17 +7,19 @@ import {
|
||||
toRefs,
|
||||
toRaw,
|
||||
} from "vue";
|
||||
import {useStore} from 'vuex'
|
||||
import { NAvatar } from "naive-ui";
|
||||
import { useStore } from "vuex";
|
||||
import { NAvatar, NIcon } from "naive-ui";
|
||||
import pubsub from "pubsub-js";
|
||||
import { getSongDetial } from "@/network/song";
|
||||
import dayjs from 'dayjs'
|
||||
import 'dayjs/locale/zh-cn'
|
||||
import duration from 'dayjs/plugin/duration'
|
||||
import { getSongDetial, getLyric } from "@/network/song";
|
||||
import dayjs from "dayjs";
|
||||
import "dayjs/locale/zh-cn";
|
||||
import duration from "dayjs/plugin/duration";
|
||||
import ArtistsSpan from "@/components/ArtistsSpan.vue";
|
||||
import svgArrowMin from "@/assets/svgs/ArrowMinimize24Regular.svg";
|
||||
import svgArrowMax from "@/assets/svgs/ArrowMaximize24Regular.svg";
|
||||
|
||||
const store = useStore()
|
||||
const showInfo = ref(false);
|
||||
const store = useStore();
|
||||
const showInfo = ref(true);
|
||||
const info = reactive({
|
||||
name: "",
|
||||
artists: [],
|
||||
@@ -26,7 +28,7 @@ const info = reactive({
|
||||
mv: 0,
|
||||
});
|
||||
|
||||
//#region 取得歌曲信息
|
||||
//#region 取得歌曲信息、歌词
|
||||
const songInfo = (id, im) => {
|
||||
getSongDetial(id)
|
||||
.then((res) => {
|
||||
@@ -36,17 +38,37 @@ const songInfo = (id, im) => {
|
||||
info.album = res.data.songs[0].al;
|
||||
info.duration = res.data.songs[0].dt;
|
||||
info.mv = res.data.songs[0].mv;
|
||||
currTime.value = '00:00'
|
||||
totalTime.value = zpTime(info.duration)
|
||||
if(im){
|
||||
const p = {...{
|
||||
currTime.value = "00:00";
|
||||
totalTime.value = zpTime(info.duration);
|
||||
if (im) {
|
||||
const p = {
|
||||
...{
|
||||
id,
|
||||
date: Date.now(),
|
||||
},
|
||||
...toRaw(info),
|
||||
};
|
||||
store.commit("savePlayed", p);
|
||||
store.commit("addToPlayingList", p);
|
||||
console.log("savePlayed");
|
||||
}
|
||||
pubsub.publish("zp.songInfo", {
|
||||
...{
|
||||
id,
|
||||
date: Date.now(),
|
||||
}, ...toRaw(info)}
|
||||
store.commit('savePlayed', p)
|
||||
store.commit('addToPlayingList', p)
|
||||
console.log('savePlayed');
|
||||
}
|
||||
},
|
||||
...toRaw(info),
|
||||
});
|
||||
})
|
||||
.catch((err) => {});
|
||||
};
|
||||
const songLyric = (id) => {
|
||||
getLyric(id)
|
||||
.then((res) => {
|
||||
if (res.data.code == 200)
|
||||
pubsub.publish("zp.lyric", res.data.lrc.lyric );
|
||||
else
|
||||
pubsub.publish("zp.lyric", null);
|
||||
})
|
||||
.catch((err) => {});
|
||||
};
|
||||
@@ -56,22 +78,23 @@ const songInfo = (id, im) => {
|
||||
let totalTime = ref("03:13");
|
||||
let currTime = ref("00:03");
|
||||
|
||||
dayjs.extend(duration)
|
||||
dayjs.extend(duration);
|
||||
function zpTime(time) {
|
||||
return dayjs.duration(time).format('mm:ss')
|
||||
return dayjs.duration(time).format("mm:ss");
|
||||
}
|
||||
// totalTime.value = zpTime(12345)
|
||||
const psToken = pubsub.subscribe("zp", (msg, data) => {
|
||||
switch (msg) {
|
||||
case "zp.getSongInfo":
|
||||
songInfo(data.id, data.im);
|
||||
songLyric(data.id);
|
||||
break;
|
||||
case "zp.hideSongInfo":
|
||||
showInfo.value = false
|
||||
showInfo.value = false;
|
||||
break;
|
||||
case "zp.progress":
|
||||
totalTime.value = zpTime(data.total * 1000)
|
||||
currTime.value = zpTime(data.progress * 1000)
|
||||
totalTime.value = zpTime(data.total * 1000);
|
||||
currTime.value = zpTime(data.progress * 1000);
|
||||
break;
|
||||
}
|
||||
});
|
||||
@@ -80,25 +103,40 @@ onUnmounted(() => {
|
||||
pubsub.unsubscribe(psToken);
|
||||
});
|
||||
//#endregion
|
||||
|
||||
const toggleSongDetail = () => {
|
||||
console.log(
|
||||
"显示/隐藏歌曲详细界面,包括歌词、模拟唱机以及其他操作。"
|
||||
);
|
||||
pubsub.publish("zp.toggleSongDetail");
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="songInfo">
|
||||
<NAvatar style="border: 1px #ccc solid;"
|
||||
:size="40"
|
||||
v-show="showInfo"
|
||||
:src="info.album.picUrl"
|
||||
></NAvatar>
|
||||
<div class="wp-img" v-show="showInfo" @click="toggleSongDetail">
|
||||
<img :src="info.album.picUrl" width="42" class="img" />
|
||||
<span class="wp-icon">
|
||||
<NIcon v-if="store.state.showSongDetail"
|
||||
><svgArrowMin
|
||||
/></NIcon>
|
||||
<NIcon v-else><svgArrowMax /></NIcon>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="song" v-show="showInfo">
|
||||
<div class="w-song">
|
||||
<div class="song-name">{{ info.name }}</div>
|
||||
<div class="song-name" @click="toggleSongDetail">
|
||||
{{ info.name }}
|
||||
</div>
|
||||
<div class="song-author">
|
||||
<ArtistsSpan :artists="info.artists" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="song-time">
|
||||
<span class="played-time">{{ currTime }}</span>/<span class="total-time">{{ totalTime }}</span>
|
||||
<div class="song-time" @click="toggleSongDetail">
|
||||
<span class="played-time">{{ currTime }}</span
|
||||
>/<span class="total-time">{{ totalTime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -116,14 +154,54 @@ export default {};
|
||||
align-items: center;
|
||||
margin-left: 12px;
|
||||
|
||||
.wp-img {
|
||||
--radius: 4px;
|
||||
|
||||
position: relative;
|
||||
border: 1px #eee solid;
|
||||
border-radius: var(--radius);
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
.wp-icon {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.img {
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
.wp-icon {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
color: #fff;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
border-radius: var(--radius);
|
||||
-webkit-backdrop-filter: blur(2px);
|
||||
backdrop-filter: blur(2px);
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 33px;
|
||||
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.song {
|
||||
padding-left: 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
cursor: pointer;
|
||||
.w-song {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.song-name{
|
||||
.song-name {
|
||||
// flex: 1;
|
||||
.text-el-line-normal();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user