基本完成歌曲详情
This commit is contained in:
parent
2701d0cfe7
commit
25af6cfedb
@ -22,6 +22,7 @@
|
|||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
"dayjs": "^1.10.7",
|
"dayjs": "^1.10.7",
|
||||||
"element-plus": "^1.1.0-beta.19",
|
"element-plus": "^1.1.0-beta.19",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"pubsub-js": "^1.9.3",
|
"pubsub-js": "^1.9.3",
|
||||||
"unplugin-vue-components": "^0.15.6",
|
"unplugin-vue-components": "^0.15.6",
|
||||||
"vue": "^3.2.16",
|
"vue": "^3.2.16",
|
||||||
|
@ -228,7 +228,7 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#wpSongDetail {
|
#wpSongDetail {
|
||||||
|
z-index: 100;
|
||||||
}
|
}
|
||||||
#wpPlayingList {
|
#wpPlayingList {
|
||||||
// position: absolute;
|
// position: absolute;
|
||||||
|
27
src/components/AlbumSpan.vue
Normal file
27
src/components/AlbumSpan.vue
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref, defineProps, onUnmounted, onDeactivated } from "vue";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
album: Object,
|
||||||
|
onLeave: Function,
|
||||||
|
});
|
||||||
|
const router = useRouter();
|
||||||
|
// console.log(props.artists);
|
||||||
|
|
||||||
|
const click = (id) => {
|
||||||
|
props.onLeave?.();
|
||||||
|
router.push("/album/" + id);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<span
|
||||||
|
@click="click(album.id)"
|
||||||
|
style="margin-right: 4px; cursor: pointer"
|
||||||
|
>{{ album.name }}</span
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script></script>
|
||||||
|
|
||||||
|
<style></style>
|
@ -2,14 +2,17 @@
|
|||||||
import { ref, defineProps, onUnmounted, onDeactivated } from "vue";
|
import { ref, defineProps, onUnmounted, onDeactivated } from "vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
|
|
||||||
const props = defineProps({ artists: Array, onLeave: Function });
|
const props = defineProps({
|
||||||
const router = useRouter()
|
artists: Array,
|
||||||
|
onLeave: Function,
|
||||||
|
});
|
||||||
|
const router = useRouter();
|
||||||
// console.log(props.artists);
|
// console.log(props.artists);
|
||||||
|
|
||||||
const click = (id) => {
|
const click = (id) => {
|
||||||
props.onLeave?.()
|
props.onLeave?.();
|
||||||
router.push('/singer/' + id)
|
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">
|
||||||
@ -22,9 +25,7 @@ const click = (id) => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// export default {
|
|
||||||
// props: ["artists"],
|
|
||||||
// };
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style></style>
|
<style></style>
|
||||||
|
@ -1,42 +1,105 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onUnmounted, watch } from "vue";
|
import { ref, onUnmounted, watch, toRaw, nextTick } from "vue";
|
||||||
import { NButton, NIcon } from "naive-ui";
|
import { NButton, NIcon } from "naive-ui";
|
||||||
import { useStore } from "vuex";
|
import { useStore } from "vuex";
|
||||||
import svgChevrongDown from "@/assets/svgs/ChevronDown.svg";
|
import svgChevrongDown from "@/assets/svgs/ChevronDown.svg";
|
||||||
import pubsub from "pubsub-js";
|
import pubsub from "pubsub-js";
|
||||||
|
import ArtistsSpan from "@/components/ArtistsSpan.vue";
|
||||||
|
import AlbumSpan from "@/components/AlbumSpan.vue";
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
|
|
||||||
const songInfo = ref(null);
|
const song = ref(null);
|
||||||
const lyric = ref(null);
|
const lyric = ref(null);
|
||||||
|
const lyArr = ref([]);
|
||||||
const coverAngle = ref(0);
|
const coverAngle = ref(0);
|
||||||
|
const currTime = ref(0);
|
||||||
|
const totalTime = ref(0);
|
||||||
|
const currentLyricLine = ref(false);
|
||||||
|
const currentLyricIdx = ref(-1);
|
||||||
|
const lyList = ref('')
|
||||||
|
|
||||||
let interval;
|
//#region 唱机
|
||||||
|
let interval = [];
|
||||||
watch(
|
watch(
|
||||||
() => store.state.settings.playing,
|
() => [store.state.settings.playing, store.state.showSongDetail],
|
||||||
(val) => {
|
([playing, showSongDetail]) => {
|
||||||
if(val){
|
if (playing && showSongDetail) {
|
||||||
interval = setInterval(() => {
|
interval.push(
|
||||||
coverAngle.value += .5
|
setInterval(() => {
|
||||||
}, 100);
|
coverAngle.value += 0.5;
|
||||||
|
}, 40)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
clearInterval(interval)
|
interval.map((item) => clearInterval(item));
|
||||||
|
interval = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
{immediate: true}
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 歌词
|
||||||
|
|
||||||
|
//处理歌词
|
||||||
|
const handleLyric = (ly) => {
|
||||||
|
lyArr.value = [];
|
||||||
|
const lines = ly.split("\n");
|
||||||
|
const re = /^\[(\d+):(\d+(.\d+)?)\](.*)$/;
|
||||||
|
lines.forEach((line) => {
|
||||||
|
// console.log(line);
|
||||||
|
// let match = re.exec(line)
|
||||||
|
// console.log(match);
|
||||||
|
// console.log(Number(line.replace(re,'$1')))
|
||||||
|
if (re.test(line))
|
||||||
|
lyArr.value.push({
|
||||||
|
time:
|
||||||
|
Number(line.replace(re, "$1")) * 60 * 1000 +
|
||||||
|
Number(line.replace(re, "$2")) * 1000,
|
||||||
|
lyric: line.replace(re, "$4"),
|
||||||
|
origin: line,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// lyList.value.scrollTop = 0;
|
||||||
|
// console.log(lyArr.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
()=> currentLyricIdx.value,
|
||||||
|
(val)=>{
|
||||||
|
if(val>0){
|
||||||
|
// let elContent = document.getElementsByClassName('ly-content')[0]
|
||||||
|
let el = document.getElementsByClassName('ly-key-lines')[val]
|
||||||
|
lyList.value.scrollTop = el.offsetTop - 100
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
//#region 处理消息订阅
|
//#region 处理消息订阅
|
||||||
|
|
||||||
const token = pubsub.subscribe("zp", (msg, data) => {
|
const token = pubsub.subscribe("zp", (msg, data) => {
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
case "zp.songInfo":
|
case "zp.songInfo":
|
||||||
console.log("SongDetail: 收到歌曲详细信息。", data);
|
// console.log("SongDetail: 收到歌曲详细信息。", data);
|
||||||
songInfo.value = data;
|
song.value = data;
|
||||||
break;
|
break;
|
||||||
case "zp.lyric":
|
case "zp.lyric":
|
||||||
lyric.value = data;
|
lyric.value = data;
|
||||||
|
handleLyric(data);
|
||||||
|
break;
|
||||||
|
case "zp.progress":
|
||||||
|
totalTime.value = data.total * 1000;
|
||||||
|
currTime.value = data.progress * 1000;
|
||||||
|
currentLyricIdx.value = _.findLastIndex(lyArr.value,(item) => {
|
||||||
|
return item.time < currTime.value;
|
||||||
|
});
|
||||||
|
// console.log(currentLyricIdx.value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -61,8 +124,9 @@ onUnmounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
</n-button>
|
</n-button>
|
||||||
</div>
|
</div>
|
||||||
<div id="sdContent" v-if="songInfo">
|
<div id="sdContent" v-if="song">
|
||||||
<div class="detail">
|
<div class="detail">
|
||||||
|
<!-- 唱机 -->
|
||||||
<div class="disk">
|
<div class="disk">
|
||||||
<div class="styli">
|
<div class="styli">
|
||||||
<img
|
<img
|
||||||
@ -74,21 +138,58 @@ onUnmounted(() => {
|
|||||||
<img class="disk" src="@/assets/images/disk.png" />
|
<img class="disk" src="@/assets/images/disk.png" />
|
||||||
<img
|
<img
|
||||||
class="cover"
|
class="cover"
|
||||||
:src="songInfo.album.picUrl"
|
:src="song.album.picUrl"
|
||||||
:style="{ transform: 'rotateZ(' + coverAngle + 'deg)' }"
|
:style="{ transform: 'rotateZ(' + coverAngle + 'deg)' }"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="pic"></div>
|
<div class="pic"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="song">
|
<div class="song">
|
||||||
歌曲
|
<div class="name">{{ song.name }}</div>
|
||||||
<div class="name"></div>
|
<div class="alias">
|
||||||
<div class="others"></div>
|
{{ song.alias.length > 0 ? song.alias.join(" ") : "" }}
|
||||||
<div class="ly"></div>
|
</div>
|
||||||
|
<div class="others">
|
||||||
|
<div class="album">
|
||||||
|
专辑:
|
||||||
|
<AlbumSpan
|
||||||
|
:album="song.album"
|
||||||
|
:onLeave="
|
||||||
|
() => {
|
||||||
|
pubsub.publish('zp.toggleSongDetail');
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="artists">
|
||||||
|
歌手:
|
||||||
|
<ArtistsSpan
|
||||||
|
:artists="song.artists"
|
||||||
|
:onLeave="
|
||||||
|
() => {
|
||||||
|
pubsub.publish('zp.toggleSongDetail');
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ly" v-if="lyric" ref="lyList">
|
||||||
|
<div class="ly-content" >
|
||||||
|
<div
|
||||||
|
class="ly-line"
|
||||||
|
v-for="(line, idx) in lyArr"
|
||||||
|
key="idx"
|
||||||
|
:class="{ current: currentLyricIdx == idx, ['ly-key-lines']: true, }"
|
||||||
|
>
|
||||||
|
{{ line.lyric }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ly-right"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="comments"></div>
|
<div class="comments"></div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -115,6 +216,7 @@ export default {};
|
|||||||
right: 0;
|
right: 0;
|
||||||
bottom: 64px;
|
bottom: 64px;
|
||||||
background-color: #f6f6f6;
|
background-color: #f6f6f6;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
.styli {
|
.styli {
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -138,7 +240,7 @@ export default {};
|
|||||||
height: 50px;
|
height: 50px;
|
||||||
}
|
}
|
||||||
.disk {
|
.disk {
|
||||||
--back-color: #eee;
|
--back-color: #ddd;
|
||||||
--width-num: 340;
|
--width-num: 340;
|
||||||
--padding-num: 10;
|
--padding-num: 10;
|
||||||
--width: calc(var(--width-num) * 1px);
|
--width: calc(var(--width-num) * 1px);
|
||||||
@ -170,7 +272,57 @@ export default {};
|
|||||||
}
|
}
|
||||||
.song {
|
.song {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 400px;
|
width: 330px;
|
||||||
|
margin-left: 30px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
.others {
|
||||||
|
// display: flex;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #999;
|
||||||
|
.album {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.artists {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ly {
|
||||||
|
position: relative;
|
||||||
|
margin-top: 15px;
|
||||||
|
height: 290px;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
// background-image : linear-gradient(180deg,hsla(255,0%,100%,0),rgba(255, 255, 255, 0.521));
|
||||||
|
|
||||||
|
.ly-content {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #999;
|
||||||
|
margin-bottom: 100px;
|
||||||
|
// display: flex;
|
||||||
|
// flex-direction: column;
|
||||||
|
// justify-items: center;
|
||||||
|
|
||||||
|
.ly-line {
|
||||||
|
min-height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.current {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ const info = reactive({
|
|||||||
name: "",
|
name: "",
|
||||||
artists: [],
|
artists: [],
|
||||||
album: {},
|
album: {},
|
||||||
|
alias: [],
|
||||||
duration: 0,
|
duration: 0,
|
||||||
mv: 0,
|
mv: 0,
|
||||||
});
|
});
|
||||||
@ -33,9 +34,11 @@ const songInfo = (id, im) => {
|
|||||||
getSongDetial(id)
|
getSongDetial(id)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
showInfo.value = true;
|
showInfo.value = true;
|
||||||
|
console.log('SongInfo: 获取歌曲详细信息',res.data.songs[0]);
|
||||||
info.name = res.data.songs[0].name;
|
info.name = res.data.songs[0].name;
|
||||||
info.artists = res.data.songs[0].ar;
|
info.artists = res.data.songs[0].ar;
|
||||||
info.album = res.data.songs[0].al;
|
info.album = res.data.songs[0].al;
|
||||||
|
info.alias = res.data.songs[0].alia;
|
||||||
info.duration = res.data.songs[0].dt;
|
info.duration = res.data.songs[0].dt;
|
||||||
info.mv = res.data.songs[0].mv;
|
info.mv = res.data.songs[0].mv;
|
||||||
currTime.value = "00:00";
|
currTime.value = "00:00";
|
||||||
@ -105,9 +108,9 @@ onUnmounted(() => {
|
|||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
const toggleSongDetail = () => {
|
const toggleSongDetail = () => {
|
||||||
console.log(
|
// console.log(
|
||||||
"显示/隐藏歌曲详细界面,包括歌词、模拟唱机以及其他操作。"
|
// "显示/隐藏歌曲详细界面,包括歌词、模拟唱机以及其他操作。"
|
||||||
);
|
// );
|
||||||
pubsub.publish("zp.toggleSongDetail");
|
pubsub.publish("zp.toggleSongDetail");
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user