初始化

This commit is contained in:
ZilongYang
2021-10-13 20:59:12 +08:00
commit 56a79617f0
73 changed files with 13328 additions and 0 deletions

5
src/views/About.vue Normal file
View File

@@ -0,0 +1,5 @@
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>

18
src/views/Home.vue Normal file
View File

@@ -0,0 +1,18 @@
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png" />
<HelloWorld msg="Welcome to Your Vue.js App" />
</div>
</template>
<script>
// @ is an alias to /src
import HelloWorld from "../components/HelloWorld.vue";
export default {
name: "Home",
components: {
HelloWorld,
},
};
</script>

View File

@@ -0,0 +1,108 @@
<script setup>
import {
h,
ref,
onMounted,
onUnmounted,
nextTick,
} from "vue";
import { useStore } from "vuex";
import {
RouterLink,
useRoute,
useRouter,
} from "vue-router";
import { NMenu, NIcon } from "naive-ui";
const menuOptions = ref([
{
label: () =>
h(
RouterLink,
{
to: {
path: "/discover/recommend",
},
},
{ default: () => "发现" }
),
key: "/discover",
},
{
label: () =>
h(
RouterLink,
{
to: {
path: "/videos/v",
},
},
{ default: () => "视频" }
),
key: "/videos",
},
{
label: () =>
h(
RouterLink,
{
to: {
path: "/played",
},
},
{ default: () => "最近播放" }
),
key: "/played",
},
//#region 其他
// {
// label: () =>
// h(
// RouterLink,
// {
// to: {
// path: '/fm'
// }
// },
// { default: () => '私人FM' }
// ),
// key: '/fm',
// },
// {
// label: () =>
// h(
// RouterLink,
// {
// to: {
// path: '/friends'
// }
// },
// { default: () => '朋友' }
// ),
// key: '/friends',
// },
//#endregion
]);
const store = useStore();
const {mainMenuSelected} = store.getters
</script>
<template>
<n-menu
:options="menuOptions"
:value="
mainMenuSelected(menuOptions)
"
/>
</template>
<script>
export default {
// beforeRouteEnter(to, from, next) {
// console.log("MainMenu beforeRouteEnter", to, from);
// next();
// },
};
</script>
<style></style>

34
src/views/common/Nav.vue Normal file
View File

@@ -0,0 +1,34 @@
<script setup>
import { useRouter } from "vue-router";
import { NButton, NIcon, NSpace } from "naive-ui";
import ChevronForward from '@/assets/svgs/ChevronForward.svg'
import ChevronBack from '@/assets/svgs/ChevronBack.svg'
const router = useRouter()
</script>
<template>
<NSpace id="nav" justify="end">
<n-button circle size="small" @click="router.back()" >
<template #icon>
<n-icon>
<ChevronBack />
</n-icon>
</template>
</n-button>
<n-button circle size="small" @click="router.forward()">
<template #icon>
<n-icon>
<ChevronForward />
</n-icon>
</template>
</n-button>
</NSpace>
</template>
<style lang="less" scoped>
#nav {
width: 150px;
// text-align: right;
// padding-top: 10px;
}
</style>

View File

@@ -0,0 +1,19 @@
<script setup>
import {NInput} from 'naive-ui'
</script>
<template>
<div id="search">
<n-input size="small" round placeholder="请搜索..." />
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>

View File

@@ -0,0 +1,39 @@
<script setup>
import { NButton, NIcon, NSpace } from "naive-ui";
import SettingsOutline from "@/assets/svgs/SettingsOutline.svg";
import MailOutline from "@/assets/svgs/MailOutline.svg";
</script>
<template>
<NSpace id="settings" >
<n-button circle size="small" >
<template #icon>
<n-icon>
<SettingsOutline />
</n-icon>
</template>
</n-button>
<n-button circle size="small" >
<template #icon>
<n-icon>
<MailOutline />
</n-icon>
</template>
</n-button>
</NSpace>
</template>
<script>
export default {
}
</script>
<style lang="less" scoped>
#settings{
// width: 100px;
margin: 0 15px
}
</style>

View File

@@ -0,0 +1,219 @@
<script setup>
import { ref, onMounted, onUnmounted, watch } from "vue";
import { useStore } from "vuex";
import { NButton, NIcon, NSpace } from "naive-ui";
import PlayCircle from "@/assets/svgs/PlayCircle.svg";
import PlaySkipForward from "@/assets/svgs/PlaySkipForward.svg";
import PlaySkipBack from "@/assets/svgs/PlaySkipBack.svg";
import HeartOutline from "@/assets/svgs/HeartOutline.svg";
import TrashOutline from "@/assets/svgs/TrashOutline.svg";
import PauseCircle from "@/assets/svgs/PauseCircle.svg";
import { getSongUrl } from "@/network/song";
import pubsub from "pubsub-js";
const store = useStore();
const { settings } = store.state;
const audioEl = ref("");
const playing = ref(false);
let currentTime = 0;
let lastPause = Date.now()
onMounted(() => {
audioEl.value.addEventListener("play", onPlay);
audioEl.value.addEventListener("pause", onPause);
audioEl.value.addEventListener("ended", onEnd);
if (settings.songId) {
pubsub.publish("zp.play", {
id: settings.songId,
im: false,
});
// play(settings.songId, false)
}
});
onUnmounted(() => {
console.log("另外一个Unmounted");
// audioEl.value.removeEventListener("play", onPlay);
// audioEl.value.removeEventListener("pause", onPause);
// audioEl.value.removeEventListener("ended", onEnd);
});
const onPlay = () => {
console.log("onPlay");
};
const onPause = () => {
console.log("onPause");
};
const onEnd = () => {
playing.value = false;
currentTime = 0;
console.log("onEnd");
};
const play = async (id, im = true) => {
console.log(id);
await getSongUrl(id)
.then((res) => {
audioEl.value.src = res.data.data[0].url;
store.commit("saveSettings", {
songId: id,
});
if (im) {
audioEl.value.play();
playing.value = true;
}
})
.catch((err) => {
console.log("getSongUrl err", err);
});
};
const pause = () => {
audioEl.value.pause();
playing.value = false;
};
const resume = async () => {
if (audioEl.value.readyState) {
//如果暂停过了5分钟需要再次载入歌曲
// console.log(Date.now() - lastPause);
if((Date.now() - lastPause) > 1000 * 60 * 5){
console.log('暂停过了5分钟再次载入歌曲');
await play(settings.songId, false);
audioEl.value.currentTime = currentTime;
}
audioEl.value.play();
playing.value = true;
}
};
const setProgressScale = (scale) => {
if (audioEl.value.readyState) {
// console.log(progress);
audioEl.value.currentTime = currentTime =
scale * audioEl.value.duration;
}
};
const favorite = () => {
// console.log(audioEl.value.currentTime);
};
let interval;
watch(playing, (val, old) => {
if (val === true) {
interval = setInterval(() => {
// console.log(audioEl.value.currentTime);
currentTime = audioEl.value.currentTime;
pubsub.publish("zp.progress", {
progress: audioEl.value.currentTime,
total: audioEl.value.duration,
});
}, 200);
} else {
clearInterval(interval);
lastPause = Date.now();
}
});
//#region 处理消息订阅
const psToken = pubsub.subscribe("zp", (msg, data) => {
switch (msg) {
case "zp.play":
play(data.id, data.im);
break;
case "zp.setProgressScale":
setProgressScale(data.scale);
break;
}
});
//卸载组件
onUnmounted(() => {
pubsub.unsubscribe(psToken);
});
//#endregion
</script>
<template>
<!-- <div id="songsCtrl"> -->
<audio src="" ref="audioEl"></audio>
<n-space
id="songCtrl"
align="center"
:size="[6]"
style="padding-top: 2px"
>
<n-button circle @click="favorite">
<template #icon>
<n-icon>
<HeartOutline />
</n-icon>
</template>
</n-button>
<n-button circle>
<template #icon>
<n-icon>
<PlaySkipBack />
</n-icon>
</template>
</n-button>
<n-button
v-if="!playing"
text
class="start-play"
style="font-size: 56px"
type="primary"
@click="resume"
>
<!-- <template #icon> -->
<n-icon>
<PlayCircle />
</n-icon>
<!-- </template> -->
</n-button>
<n-button
v-if="playing"
text
class="start-play"
style="font-size: 56px"
type="primary"
@click="pause"
>
<!-- <template #icon> -->
<n-icon size="56">
<PauseCircle />
</n-icon>
<!-- </template> -->
</n-button>
<!-- <n-button circle color="#18a058"> -->
<n-button circle>
<template #icon>
<n-icon>
<PlaySkipForward />
</n-icon>
</template>
</n-button>
<n-button circle>
<template #icon>
<n-icon>
<TrashOutline />
</n-icon>
</template>
</n-button>
</n-space>
<!-- </div> -->
</template>
<script>
export default {};
</script>
<style lang="less" scoped>
#songCtrl {
display: flex;
align-items: center;
}
</style>

View File

@@ -0,0 +1,115 @@
<script setup>
import {
ref,
onUnmounted,
reactive,
toRef,
toRefs,
} from "vue";
import { NAvatar } 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'
const showInfo = ref(true);
const info = reactive({
name: "",
artists: "",
albumPicUrl: "",
});
//#region 取得歌曲信息
const songInfo = (id) => {
getSongDetial(id)
.then((res) => {
showInfo.value = true;
info.name = res.data.songs[0].name;
info.artists = res.data.songs[0].ar[0].name;
info.albumPicUrl = res.data.songs[0].al.picUrl;
})
.catch((err) => {});
};
//#endregion
//#region 处理消息订阅
let totalTime = ref("03:13");
let currTime = ref("00:03");
dayjs.extend(duration)
function zpTime(time) {
return dayjs.duration(time).format('mm:ss')
}
// totalTime.value = zpTime(12345)
const psToken = pubsub.subscribe("zp", (msg, data) => {
switch (msg) {
case "zp.play":
songInfo(data.id);
break;
case "zp.progress":
totalTime.value = zpTime(data.total * 1000)
currTime.value = zpTime(data.progress * 1000)
break;
}
});
//卸载组件
onUnmounted(() => {
pubsub.unsubscribe(psToken);
});
//#endregion
</script>
<template>
<div id="songInfo">
<NAvatar
:size="40"
v-show="showInfo"
:src="info.albumPicUrl"
></NAvatar>
<div class="song" v-show="showInfo">
<div class="w-song">
<div class="song-name">{{ info.name }}</div>
<div class="song-author">{{ info.artists }}</div>
</div>
<div class="song-time">
<span class="played-time">{{ currTime }}</span>/<span class="total-time">{{ totalTime }}</span>
</div>
</div>
</div>
</template>
<script>
export default {};
</script>
<style lang="less" scoped>
#songInfo {
flex: 3;
display: flex;
align-items: center;
margin-left: 12px;
.song {
padding-left: 6px;
display: flex;
flex-direction: column;
.w-song {
display: flex;
align-items: center;
.song-author {
margin-left: 4px;
color: #aaa;
font-size: 13px;
}
}
.song-time {
color: #aaa;
font-size: 13px;
font-family: Courier, monospace;
}
}
}
</style>

View File

@@ -0,0 +1,114 @@
<script setup>
import {
ref,
onUnmounted,
reactive,
toRef,
toRefs,
} from "vue";
import { useStore } from "vuex";
import { NProgress } 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";
const store = useStore();
const progress = ref("");
const wpProgress = ref("");
const setTime = (e) => {
//设定状态条长度
rightDot.value = wpProgress.value.clientWidth - e.offsetX + 'px'
percentage.value = e.offsetX / wpProgress.value.clientWidth * 100
// console.log(rightDot.value);
//发布 设置进度条消息
pubsub.publish("zp.setProgressScale", {
scale: e.offsetX / wpProgress.value.clientWidth,
});
};
// const primaryColor = store.state.theme.themeOverrides.common.primaryColor;
const rightDot = ref("px");
//#region 处理消息订阅
let percentage = ref(0.0);
const psToken = pubsub.subscribe("zp", (msg, data) => {
switch (msg) {
case "zp.progress":
percentage.value = (data.progress * 100) / data.total;
rightDot.value =
(1 - data.progress / (data.total - 0)) *
wpProgress.value.clientWidth +
"px";
// console.log(rightDot.value);
break;
}
});
//卸载组件
onUnmounted(() => {
pubsub.unsubscribe(psToken);
});
//#endregion
</script>
<template>
<div id="wpProgress" ref="wpProgress">
<n-progress
class="progress"
type="line"
:percentage="percentage"
:show-indicator="false"
:color="
store.state.theme.themeOverrides.common.primaryColor
"
:height="3"
:border-radius="0"
ref="progress"
@click="setTime"
/>
<div
class="dot"
:style="{
backgroundColor:
store.state.theme.themeOverrides.common
.primaryColor,
right: rightDot,
}"
></div>
</div>
</template>
<script>
export default {};
</script>
<style lang="less" scope>
#wpProgress {
position: relative;
// overflow: visible;
::-webkit-scrollbar {
display: none;
}
.progress {
cursor: pointer;
}
.dot {
position: absolute;
// background-color: red;
height: 10px;
width: 10px;
border-radius: 6px;
top: -4px;
// left: -4px;
display: none;
}
&:hover {
.dot {
display: block;
}
}
}
</style>

View File

@@ -0,0 +1,83 @@
<script setup>
import { ref } from "vue";
import { NButton, NIcon, NSpace } from "naive-ui";
import PlaylistMusic from "@/assets/svgs/PlaylistMusic.svg";
import VolumeOffOutline from "@/assets/svgs/VolumeOffOutline.svg";
import RepeatOutline from "@/assets/svgs/RepeatOutline.svg";
import RepeatOne from "@/assets/svgs/RepeatOne.svg";
import Playlist from "@/assets/svgs/Playlist.svg";
import Random from "@/assets/svgs/Random.svg";
//播放模式0-3顺序循环单曲随机。
const playMode = ref(0)
</script>
<template>
<!-- <div id="songsCtrl"> -->
<n-space
id="songStatus"
justify="end"
align="center"
:size="[6]"
style="padding-top: 2px; padding-right: 8px"
>
<n-button circle v-if="playMode==1">
<template #icon>
<n-icon>
<RepeatOutline />
</n-icon>
</template>
</n-button>
<n-button circle v-if="playMode==2">
<template #icon>
<n-icon>
<RepeatOne />
</n-icon>
</template>
</n-button>
<n-button circle v-if="playMode==0">
<template #icon>
<n-icon>
<Playlist />
</n-icon>
</template>
</n-button>
<n-button circle v-if="playMode==3">
<template #icon>
<n-icon>
<Random />
</n-icon>
</template>
</n-button>
<n-button circle>
<template #icon>
<n-icon>
<PlaylistMusic />
</n-icon>
</template>
</n-button>
<n-button circle>
<template #icon>
<n-icon>
<VolumeOffOutline />
</n-icon>
</template>
</n-button>
</n-space>
<!-- </div> -->
</template>
<script>
export default {
}
</script>
<style lang="less" scoped>
#songStatus {
flex: 2;
}
</style>

View File

@@ -0,0 +1,18 @@
<template>
<div id="topmenu">
</div>
</template>
<script>
export default {
}
</script>
<style lang="less" scoped>
#topmenu{
flex: 1;
}
</style>

View File

View File

@@ -0,0 +1,130 @@
<script setup>
import { h, ref, onMounted, onUnmounted } from "vue";
import {
RouterLink,
useRoute,
useRouter,
onBeforeRouteUpdate,
onBeforeRouteLeave,
} from "vue-router";
import {
NButton,
NSpace,
NIcon,
NMenu,
NScrollbar,
} from "naive-ui";
const menuOptions = [
{
label: () =>
h(
RouterLink,
{
to: {
path: "/discover/recommend",
},
},
{ default: () => "推荐" }
),
key: "/discover/recommend",
},
{
label: () =>
h(
RouterLink,
{
to: {
path: "/discover/songlist",
},
},
{ default: () => "歌单" }
),
key: "/discover/songlist",
},
{
label: () =>
h(
RouterLink,
{
to: {
path: "/discover/anchor",
},
},
{ default: () => "主播" }
),
key: "/discover/anchor",
},
{
label: () =>
h(
RouterLink,
{
to: {
path: "/discover/ranking",
},
},
{ default: () => "排行" }
),
key: "/discover/ranking",
},
{
label: () =>
h(
RouterLink,
{
to: {
path: "/discover/singer",
},
},
{ default: () => "歌手" }
),
key: "/discover/singer",
},
{
label: () =>
h(
RouterLink,
{
to: {
path: "/discover/latest",
},
},
{ default: () => "最新" }
),
key: "/discover/latest",
},
];
const route = useRoute();
</script>
<template>
<div class="top-menu">
<n-menu
:options="menuOptions"
mode="horizontal"
class="zm-top-menu"
:value="route.path"
/>
</div>
<div class="main-content">
<NScrollbar >
<div class="ld-width">
<router-view />
</div>
</NScrollbar>
</div>
</template>
<script>
export default {
// beforeRouteEnter(to, from, next) {
// // console.log('Discover beforeRouteEnter', to, from);
// next();
// },
};
</script>
<style lang="less" scoped>
</style>

View File

View File

View File

@@ -0,0 +1,410 @@
<template>
<div class="lmt-width">
<n-carousel
show-arrow
trigger="hover"
:autoplay="true"
style="margin: 0 auto; max-width: 800px"
>
<div
class="wp-carousel"
v-for="(b, idx) in banners"
:key="idx"
>
<img class="carousel-img" :src="b.imageUrl" />
<span class="title">{{ b.typeTitle }}</span>
</div>
</n-carousel>
<!-- 最新音乐 -->
<div>
<n-button
text
icon-placement="right"
size="large"
type="primary"
style="font-size: 1.3em; margin-top: 6px"
>
<template #icon>
<n-icon>
<ChevronForward />
</n-icon>
</template>
最新音乐
</n-button>
<n-grid
:x-gap="18"
:y-gap="8"
:cols="2"
style="margin: 6px 0"
>
<n-grid-item
v-for="(song, idx) in topSongs"
key="idx"
>
<div class="c2-list">
<div class="play-btn">
<img :src="song.album.blurPicUrl" />
<n-button
text
class="start-play-bg"
type="info"
>
<n-icon>
<PlayCircle @click="play(song.id)" />
</n-icon>
</n-button>
<n-button
text
class="start-play"
type="primary"
>
<n-icon>
<Play @click="play(song.id)"/>
</n-icon>
</n-button>
</div>
<div class="title">
<span class="name">
{{ song.name }}
<span class="alias">{{
songAlias(song.alias)
}}</span>
</span>
<span class="artist">{{
songArtists(song.artists)
}}</span>
</div>
<span class="icon"></span>
</div>
</n-grid-item>
</n-grid>
</div>
<!-- 推荐MV -->
<div>
<!-- 标题 -->
<n-button
text
icon-placement="right"
size="large"
type="primary"
style="font-size: 1.3em; margin-top: 6px"
>
<template #icon>
<n-icon>
<ChevronForward />
</n-icon>
</template>
推荐MV
</n-button>
<!-- 列表 -->
<n-grid
:x-gap="18"
:y-gap="8"
:cols="4"
style="margin: 6px 0"
>
<n-grid-item
v-for="(mv, idx) in personalizedMV"
key="idx"
>
<div class="mv-c2-list">
<div class="play-mv">
<div>
<img :src="mv.picUrl" />
</div>
<n-button
text
class="start-play-bg"
type="info"
>
<n-icon>
<PlayCircle />
</n-icon>
</n-button>
<n-button
text
class="start-play"
type="primary"
>
<n-icon>
<Play />
</n-icon>
</n-button>
</div>
<div class="title">
<span class="name">
{{ mv.name }}
</span>
<span class="artist">{{
mv.artistName
}}</span>
</div>
</div>
</n-grid-item>
</n-grid>
</div>
<!-- 推荐歌单 -->
<div>
<n-button
text
icon-placement="right"
size="large"
type="primary"
style="font-size: 1.3em; margin-top: 6px"
>
<template #icon>
<n-icon>
<ChevronForward />
</n-icon>
</template>
推荐歌单
</n-button>
<n-grid
:x-gap="18"
:y-gap="8"
:cols="4"
style="margin: 6px 0"
>
<n-grid-item v-for="p in personalized">
<n-card
title
hoverable
content-style="padding: 2px 6px;"
>
<template #cover>
<img :src="p.picUrl" />
</template>
<span class="card-span">{{ p.name }}</span>
</n-card>
</n-grid-item>
</n-grid>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
import { useStore } from "vuex";
import {
NCarousel,
NScrollbar,
NGrid,
NGridItem,
NCard,
NButton,
NIcon,
NImage,
} from "naive-ui";
// import {
// ChevronForward,
// PlayCircle,
// Play,
// } from "@vicons/ionicons5";
import PlayCircle from "@/assets/svgs/PlayCircle.svg";
import Play from "@/assets/svgs/Play_.svg";
import ChevronForward from "@/assets/svgs/ChevronForward.svg";
import {
getBanner,
getPersonalized,
getTopSong,
getPersonalizedMV,
} from "@/network/discover";
import pubsub from 'pubsub-js'
const store = useStore();
const play=(id)=>{
pubsub.publish('zp.play', {id, im: true})
}
//#region 初始载入数据
//轮播图片
let banners = ref([]);
getBanner(0)
.then((res) => {
banners.value = res.data.banners;
// console.log(banners.value);
})
.catch((err) => {
console.log("getBanner err", err);
});
//最新音乐
let topSongs = ref([]);
getTopSong()
.then((res) => {
topSongs.value = res.data.data.filter((item, index) => {
return index < 10;
});
// console.log(topSongs.value);
})
.catch((err) => {
console.log("getTopSong err", err);
});
function songAlias(alias) {
if (alias.length > 0) return "[" + alias.join(",") + "]";
}
function songArtists(artists) {
if (artists.length > 0) {
return artists
.map((a) => {
return a.name;
})
.join(" ");
}
}
//推荐歌单
let personalized = ref([]);
getPersonalized(8)
.then((res) => {
personalized.value = res.data.result;
// console.log(personalized.value);
})
.catch((err) => {
console.log("getPersonalized err", err);
});
//推荐MV
let personalizedMV = ref([]);
getPersonalizedMV()
.then((res) => {
personalizedMV.value = res.data.result;
// console.log(personalized.value);
})
.catch((err) => {
console.log("getPersonalizedMV err", err);
});
//#endregion
</script>
<style lang="less" scoped>
@import "@/assets/css/common.less";
.wp-carousel {
position: relative;
// width: 20em;
// font-size: 1vw;
.carousel-img {
width: 100%;
border-radius: 6px;
}
.title {
position: absolute;
color: #fff;
background-color: #5c18a0ff;
bottom: 0px;
right: 0;
padding: 2px 6px;
font-size: 0.9em;
border-top-left-radius: 6px;
border-bottom-right-radius: 6px;
}
}
.card-span {
.text-el-line2();
}
.mv-c2-list {
display: flex;
flex-direction: column;
position: relative;
border: 1px solid #eee;
border-radius: 6px;
.play-mv {
img {
width: 100%;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
}
button{
display: none;
}
.start-play-bg{
font-size: 38px;
position: absolute;
right: 0px;
bottom: 42px;
color: rgba(255, 255, 255, 0.8);
}
.start-play{
font-size: 25px;
position: absolute;
right: 5px;
bottom: 48px;
}
&:hover{
button{
display: block;
}
}
}
.title {
padding: 3px;
.name {
.text-el-line();
.alias {
font-size: 13px;
color: #888;
}
}
.artist {
font-size: 13px;
color: #666;
.text-el-line();
}
}
}
.c2-list {
display: flex;
align-items: center;
position: relative;
border-radius: 4px;
border: 1px solid #eee;
img {
width: 60px;
border-radius: 4px;
}
.start-play-bg{
font-size: 30px;
position: absolute;
left: 16px;
top: 17px;
color: rgba(255, 255, 255, 0.8);
}
.start-play{
font-size: 16px;
position: absolute;
left: 24px;
top: 24px;
}
.title {
padding-left: 8px;
display: flex;
flex-direction: column;
.name {
.text-el-line();
.alias {
font-size: 13px;
color: #888;
}
}
.artist {
font-size: 13px;
color: #666;
.text-el-line();
}
}
// .icon {
// }
}
</style>

View File

View File

13
src/views/fm/FM.vue Normal file
View File

@@ -0,0 +1,13 @@
<template>
FM
</template>
<script>
export default {
}
</script>
<style>
</style>

View File

@@ -0,0 +1,13 @@
<template>
朋友
</template>
<script>
export default {
}
</script>
<style>
</style>

0
src/views/videos/MV.vue Normal file
View File

0
src/views/videos/V.vue Normal file
View File

View File

@@ -0,0 +1,57 @@
<script setup>
import { h } from "vue";
import { RouterLink, useRoute } from "vue-router";
import { NButton, NSpace, NIcon, NMenu } from "naive-ui";
const menuOptions = [
{
label: () =>
h(
RouterLink,
{
to: {
path: "/videos/v",
},
},
{ default: () => "视频" }
),
key: "/videos/v",
},
{
label: () =>
h(
RouterLink,
{
to: {
path: "/videos/mv",
},
},
{ default: () => "MV" }
),
key: "/videos/mv",
}
];
const route = useRoute()
</script>
<template>
<div class="top-menu">
<n-menu
:options="menuOptions"
mode="horizontal"
class="zm-top-menu"
:value="route.path"
/>
</div>
<router-view />
</template>
<script>
export default {
}
</script>
<style>
</style>