mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-24 16:27:23 +08:00
🎈 perf: 优化加载 升级vue3.5 electron32等多个包 添加v-loading指令
This commit is contained in:
Vendored
+1
-2
@@ -1,10 +1,10 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
/* prettier-ignore */
|
|
||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
// Generated by unplugin-vue-components
|
// Generated by unplugin-vue-components
|
||||||
// Read more: https://github.com/vuejs/core/pull/3399
|
// Read more: https://github.com/vuejs/core/pull/3399
|
||||||
export {}
|
export {}
|
||||||
|
|
||||||
|
/* prettier-ignore */
|
||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
MPop: typeof import('./src/components/common/MPop.vue')['default']
|
MPop: typeof import('./src/components/common/MPop.vue')['default']
|
||||||
@@ -23,7 +23,6 @@ declare module 'vue' {
|
|||||||
NPopover: typeof import('naive-ui')['NPopover']
|
NPopover: typeof import('naive-ui')['NPopover']
|
||||||
NScrollbar: typeof import('naive-ui')['NScrollbar']
|
NScrollbar: typeof import('naive-ui')['NScrollbar']
|
||||||
NSlider: typeof import('naive-ui')['NSlider']
|
NSlider: typeof import('naive-ui')['NSlider']
|
||||||
NSpin: typeof import('naive-ui')['NSpin']
|
|
||||||
NSwitch: typeof import('naive-ui')['NSwitch']
|
NSwitch: typeof import('naive-ui')['NSwitch']
|
||||||
NTooltip: typeof import('naive-ui')['NTooltip']
|
NTooltip: typeof import('naive-ui')['NTooltip']
|
||||||
PlayBottom: typeof import('./src/components/common/PlayBottom.vue')['default']
|
PlayBottom: typeof import('./src/components/common/PlayBottom.vue')['default']
|
||||||
|
|||||||
+23
-23
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "alger-music",
|
"name": "alger-music",
|
||||||
"version": "1.5.1",
|
"version": "1.6.0",
|
||||||
"description": "这是一个用于音乐播放的应用程序。",
|
"description": "这是一个用于音乐播放的应用程序。",
|
||||||
"author": "Alger <algerkc@qq.com>",
|
"author": "Alger <algerkc@qq.com>",
|
||||||
"main": "app.js",
|
"main": "app.js",
|
||||||
@@ -21,16 +21,16 @@
|
|||||||
"@tailwindcss/postcss7-compat": "^2.2.4",
|
"@tailwindcss/postcss7-compat": "^2.2.4",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
||||||
"@typescript-eslint/parser": "^6.21.0",
|
"@typescript-eslint/parser": "^6.21.0",
|
||||||
"@vitejs/plugin-vue": "^4.2.3",
|
"@vitejs/plugin-vue": "^5.1.3",
|
||||||
"@vue/compiler-sfc": "^3.3.4",
|
"@vue/compiler-sfc": "^3.5.0",
|
||||||
"@vue/eslint-config-typescript": "^12.0.0",
|
"@vue/eslint-config-typescript": "^13.0.0",
|
||||||
"@vue/runtime-core": "^3.3.4",
|
"@vue/runtime-core": "^3.5.0",
|
||||||
"@vueuse/core": "^10.7.1",
|
"@vueuse/core": "^11.0.3",
|
||||||
"@vueuse/electron": "^10.9.0",
|
"@vueuse/electron": "^11.0.3",
|
||||||
"autoprefixer": "^9.8.6",
|
"autoprefixer": "^10.4.20",
|
||||||
"axios": "^0.21.1",
|
"axios": "^1.7.7",
|
||||||
"electron": "^30.0.0",
|
"electron": "^32.0.1",
|
||||||
"electron-builder": "^24.13.0",
|
"electron-builder": "^25.0.5",
|
||||||
"eslint": "^8.56.0",
|
"eslint": "^8.56.0",
|
||||||
"eslint-config-airbnb-base": "^15.0.0",
|
"eslint-config-airbnb-base": "^15.0.0",
|
||||||
"eslint-config-prettier": "^9.0.0",
|
"eslint-config-prettier": "^9.0.0",
|
||||||
@@ -40,22 +40,22 @@
|
|||||||
"eslint-plugin-vue": "^9.21.1",
|
"eslint-plugin-vue": "^9.21.1",
|
||||||
"eslint-plugin-vue-scoped-css": "^2.7.2",
|
"eslint-plugin-vue-scoped-css": "^2.7.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"naive-ui": "^2.38.2",
|
"naive-ui": "^2.39.0",
|
||||||
"postcss": "^7.0.36",
|
"postcss": "^8.4.44",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.3.3",
|
||||||
"remixicon": "^4.2.0",
|
"remixicon": "^4.2.0",
|
||||||
"sass": "^1.35.2",
|
"sass": "^1.78.0",
|
||||||
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.4",
|
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.4",
|
||||||
"typescript": "^4.3.2",
|
"typescript": "^5.5.4",
|
||||||
"unplugin-auto-import": "^0.17.2",
|
"unplugin-auto-import": "^0.18.2",
|
||||||
"unplugin-vue-components": "^0.26.0",
|
"unplugin-vue-components": "^0.27.4",
|
||||||
"vfonts": "^0.1.0",
|
"vfonts": "^0.1.0",
|
||||||
"vite": "^4.4.7",
|
"vite": "^5.4.3",
|
||||||
"vite-plugin-compression": "^0.5.1",
|
"vite-plugin-compression": "^0.5.1",
|
||||||
"vite-plugin-vue-devtools": "1.0.0-beta.5",
|
"vite-plugin-vue-devtools": "7.4.0",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.5.0",
|
||||||
"vue-router": "^4.2.4",
|
"vue-router": "^4.4.3",
|
||||||
"vue-tsc": "^0.0.24",
|
"vue-tsc": "^2.1.4",
|
||||||
"vuex": "^4.1.0"
|
"vuex": "^4.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,20 +9,18 @@
|
|||||||
<i class="iconfont icon-icon_error music-close" @click="close"></i>
|
<i class="iconfont icon-icon_error music-close" @click="close"></i>
|
||||||
<div class="music-title text-el">{{ name }}</div>
|
<div class="music-title text-el">{{ name }}</div>
|
||||||
<!-- 歌单歌曲列表 -->
|
<!-- 歌单歌曲列表 -->
|
||||||
<div :show="loading" class="music-list">
|
<div class="music-list">
|
||||||
<n-scrollbar>
|
<n-scrollbar>
|
||||||
<n-spin :show="loading">
|
<div v-loading="loading || !songList.length" class="music-list-content">
|
||||||
<div class="music-list-content">
|
<div
|
||||||
<div
|
v-for="(item, index) in songList"
|
||||||
v-for="(item, index) in songList"
|
:key="item.id"
|
||||||
:key="item.id"
|
:class="setAnimationClass('animate__bounceInLeft')"
|
||||||
:class="setAnimationClass('animate__bounceInUp')"
|
:style="setAnimationDelay(index, 50)"
|
||||||
:style="setAnimationDelay(index, 50)"
|
>
|
||||||
>
|
<song-item :item="formatDetail(item)" @play="handlePlay" />
|
||||||
<song-item :item="formatDetail(item)" @play="handlePlay" />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</n-spin>
|
</div>
|
||||||
<play-bottom />
|
<play-bottom />
|
||||||
</n-scrollbar>
|
</n-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
@@ -38,24 +36,15 @@ import { isMobile, setAnimationClass, setAnimationDelay } from '@/utils';
|
|||||||
|
|
||||||
import PlayBottom from './common/PlayBottom.vue';
|
import PlayBottom from './common/PlayBottom.vue';
|
||||||
|
|
||||||
const loading = ref(true);
|
|
||||||
|
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
|
|
||||||
const props = defineProps<{
|
const { songList, loading = false } = defineProps<{
|
||||||
show: boolean;
|
show: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
songList: any[];
|
songList: any[];
|
||||||
|
loading?: boolean;
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits(['update:show']);
|
const emit = defineEmits(['update:show', 'update:loading']);
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.songList,
|
|
||||||
(val) => {
|
|
||||||
loading.value = !(val && val.length);
|
|
||||||
},
|
|
||||||
{ immediate: true },
|
|
||||||
);
|
|
||||||
|
|
||||||
const formatDetail = computed(() => (detail: any) => {
|
const formatDetail = computed(() => (detail: any) => {
|
||||||
const song = {
|
const song = {
|
||||||
@@ -70,7 +59,7 @@ const formatDetail = computed(() => (detail: any) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handlePlay = () => {
|
const handlePlay = () => {
|
||||||
const tracks = props.songList || [];
|
const tracks = songList || [];
|
||||||
store.commit('setPlayList', tracks);
|
store.commit('setPlayList', tracks);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<div class="recommend-singer">
|
<div class="recommend-singer">
|
||||||
<div class="recommend-singer-list">
|
<div class="recommend-singer-list">
|
||||||
<div
|
<div
|
||||||
|
v-if="dayRecommendData"
|
||||||
class="recommend-singer-item relative"
|
class="recommend-singer-item relative"
|
||||||
:class="setAnimationClass('animate__backInRight')"
|
:class="setAnimationClass('animate__backInRight')"
|
||||||
:style="setAnimationDelay(0, 100)"
|
:style="setAnimationDelay(0, 100)"
|
||||||
@@ -27,7 +28,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-for="(item, index) in hotSingerData?.artists.slice(0, 4)"
|
v-for="(item, index) in hotSingerData?.artists"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
class="recommend-singer-item relative"
|
class="recommend-singer-item relative"
|
||||||
:class="setAnimationClass('animate__backInRight')"
|
:class="setAnimationClass('animate__backInRight')"
|
||||||
@@ -59,6 +60,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
import { useStore } from 'vuex';
|
||||||
|
|
||||||
import { getDayRecommend, getHotSinger } from '@/api/home';
|
import { getDayRecommend, getHotSinger } from '@/api/home';
|
||||||
import router from '@/router';
|
import router from '@/router';
|
||||||
@@ -66,6 +68,8 @@ import { IDayRecommend } from '@/type/day_recommend';
|
|||||||
import type { IHotSinger } from '@/type/singer';
|
import type { IHotSinger } from '@/type/singer';
|
||||||
import { getImgUrl, setAnimationClass, setAnimationDelay, setBackgroundImg } from '@/utils';
|
import { getImgUrl, setAnimationClass, setAnimationDelay, setBackgroundImg } from '@/utils';
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
|
||||||
// 歌手信息
|
// 歌手信息
|
||||||
const hotSingerData = ref<IHotSinger>();
|
const hotSingerData = ref<IHotSinger>();
|
||||||
const dayRecommendData = ref<IDayRecommend>();
|
const dayRecommendData = ref<IDayRecommend>();
|
||||||
@@ -82,18 +86,24 @@ const showMusic = ref(false);
|
|||||||
// };
|
// };
|
||||||
// 页面初始化
|
// 页面初始化
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
await loadData();
|
||||||
|
});
|
||||||
|
|
||||||
|
const loadData = async () => {
|
||||||
try {
|
try {
|
||||||
const [{ data: singerData }, { data: dayRecommend }] = await Promise.all([
|
const [{ data: singerData }, { data: dayRecommend }] = await Promise.all([
|
||||||
getHotSinger({ offset: 0, limit: 5 }),
|
getHotSinger({ offset: 0, limit: 5 }),
|
||||||
getDayRecommend(),
|
getDayRecommend(),
|
||||||
]);
|
]);
|
||||||
|
if (dayRecommend.data) {
|
||||||
|
singerData.artists = singerData.artists.slice(0, 4);
|
||||||
|
}
|
||||||
hotSingerData.value = singerData;
|
hotSingerData.value = singerData;
|
||||||
dayRecommendData.value = dayRecommend.data;
|
dayRecommendData.value = dayRecommend.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('error', error);
|
console.error('error', error);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
const toSearchSinger = (keyword: string) => {
|
const toSearchSinger = (keyword: string) => {
|
||||||
router.push({
|
router.push({
|
||||||
@@ -103,6 +113,13 @@ const toSearchSinger = (keyword: string) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 监听登录状态
|
||||||
|
watchEffect(() => {
|
||||||
|
if (store.state.user) {
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="recommend-music">
|
<div class="recommend-music">
|
||||||
<div class="title" :class="setAnimationClass('animate__fadeInLeft')">本周最热音乐</div>
|
<div class="title" :class="setAnimationClass('animate__fadeInLeft')">本周最热音乐</div>
|
||||||
<div v-show="recommendMusic?.result" class="recommend-music-list" :class="setAnimationClass('animate__bounceInUp')">
|
<div
|
||||||
|
v-show="recommendMusic?.result"
|
||||||
|
v-loading="loading"
|
||||||
|
class="recommend-music-list"
|
||||||
|
:class="setAnimationClass('animate__bounceInUp')"
|
||||||
|
>
|
||||||
<!-- 推荐音乐列表 -->
|
<!-- 推荐音乐列表 -->
|
||||||
<template v-for="(item, index) in recommendMusic?.result" :key="item.id">
|
<template v-for="(item, index) in recommendMusic?.result" :key="item.id">
|
||||||
<div :class="setAnimationClass('animate__bounceInUp')" :style="setAnimationDelay(index, 100)">
|
<div :class="setAnimationClass('animate__bounceInUp')" :style="setAnimationDelay(index, 100)">
|
||||||
@@ -24,11 +29,14 @@ import SongItem from './common/SongItem.vue';
|
|||||||
const store = useStore();
|
const store = useStore();
|
||||||
// 推荐歌曲
|
// 推荐歌曲
|
||||||
const recommendMusic = ref<IRecommendMusic>();
|
const recommendMusic = ref<IRecommendMusic>();
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
// 加载推荐歌曲
|
// 加载推荐歌曲
|
||||||
const loadRecommendMusic = async () => {
|
const loadRecommendMusic = async () => {
|
||||||
|
loading.value = true;
|
||||||
const { data } = await getRecommendMusic({ limit: 10 });
|
const { data } = await getRecommendMusic({ limit: 10 });
|
||||||
recommendMusic.value = data;
|
recommendMusic.value = data;
|
||||||
|
loading.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 页面初始化
|
// 页面初始化
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { vLoading } from './loading/index';
|
||||||
|
|
||||||
|
const directives = {
|
||||||
|
loading: vLoading,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default directives;
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { createVNode, render, VNode } from 'vue';
|
||||||
|
|
||||||
|
import Loading from './index.vue';
|
||||||
|
|
||||||
|
const vnode: VNode = createVNode(Loading) as VNode;
|
||||||
|
|
||||||
|
export const vLoading = {
|
||||||
|
// 在绑定元素的父组件 及他自己的所有子节点都挂载完成后调用
|
||||||
|
mounted: (el: HTMLElement, binding: any) => {
|
||||||
|
render(vnode, el);
|
||||||
|
},
|
||||||
|
// 在绑定元素的父组件 及他自己的所有子节点都更新后调用
|
||||||
|
updated: (el: HTMLElement, binding: any) => {
|
||||||
|
if (binding.value) {
|
||||||
|
vnode?.component?.exposed.show();
|
||||||
|
} else {
|
||||||
|
vnode?.component?.exposed.hide();
|
||||||
|
}
|
||||||
|
// 动态添加删除自定义class: loading-parent
|
||||||
|
formatterClass(el, binding);
|
||||||
|
},
|
||||||
|
// 绑定元素的父组件卸载后调用
|
||||||
|
unmounted: () => {
|
||||||
|
vnode?.component?.exposed.hide();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function formatterClass(el: HTMLElement, binding: any) {
|
||||||
|
const classStr = el.getAttribute('class');
|
||||||
|
const tagetClass: number = classStr?.indexOf('loading-parent') as number;
|
||||||
|
if (binding.value) {
|
||||||
|
if (tagetClass === -1) {
|
||||||
|
el.setAttribute('class', `${classStr} loading-parent`);
|
||||||
|
}
|
||||||
|
} else if (tagetClass > -1) {
|
||||||
|
const classArray: Array<string> = classStr?.split('') as string[];
|
||||||
|
classArray.splice(tagetClass - 1, tagetClass + 15);
|
||||||
|
el.setAttribute('class', classArray?.join(''));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
<!-- -->
|
||||||
|
<template>
|
||||||
|
<div v-if="isShow" class="loading-box">
|
||||||
|
<div class="mask" :style="{ background: maskBackground }"></div>
|
||||||
|
<div class="loading-content-box">
|
||||||
|
<n-spin size="small" />
|
||||||
|
<div :style="{ color: textColor }" class="tip">{{ tip }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { NSpin } from 'naive-ui';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
tip: {
|
||||||
|
type: String,
|
||||||
|
default() {
|
||||||
|
return '加载中...';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
maskBackground: {
|
||||||
|
type: String,
|
||||||
|
default() {
|
||||||
|
return 'rgba(0, 0, 0, 0.8)';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
loadingColor: {
|
||||||
|
type: String,
|
||||||
|
default() {
|
||||||
|
return 'rgba(255, 255, 255, 1)';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
textColor: {
|
||||||
|
type: String,
|
||||||
|
default() {
|
||||||
|
return 'rgba(255, 255, 255, 1)';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const isShow = ref(false);
|
||||||
|
const show = () => {
|
||||||
|
isShow.value = true;
|
||||||
|
};
|
||||||
|
const hide = () => {
|
||||||
|
isShow.value = false;
|
||||||
|
};
|
||||||
|
defineExpose({
|
||||||
|
show,
|
||||||
|
hide,
|
||||||
|
isShow,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.loading-box {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
z-index: 9999;
|
||||||
|
.n-spin {
|
||||||
|
// color: #ccc;
|
||||||
|
}
|
||||||
|
.mask {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.loading-content-box {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.tip {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -10,8 +10,13 @@ import router from '@/router';
|
|||||||
import store from '@/store';
|
import store from '@/store';
|
||||||
|
|
||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
|
import directives from './directive';
|
||||||
|
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
|
|
||||||
|
Object.keys(directives).forEach((key: string) => {
|
||||||
|
app.directive(key, directives[key]);
|
||||||
|
});
|
||||||
app.use(router);
|
app.use(router);
|
||||||
app.use(store);
|
app.use(store);
|
||||||
app.mount('#app');
|
app.mount('#app');
|
||||||
|
|||||||
@@ -16,19 +16,24 @@ const showMusic = ref(false);
|
|||||||
|
|
||||||
const recommendItem = ref<IRecommendItem | null>();
|
const recommendItem = ref<IRecommendItem | null>();
|
||||||
const listDetail = ref<IListDetail | null>();
|
const listDetail = ref<IListDetail | null>();
|
||||||
|
const listLoading = ref(true);
|
||||||
const selectRecommendItem = async (item: IRecommendItem) => {
|
const selectRecommendItem = async (item: IRecommendItem) => {
|
||||||
|
listLoading.value = true;
|
||||||
recommendItem.value = null;
|
recommendItem.value = null;
|
||||||
listDetail.value = null;
|
listDetail.value = null;
|
||||||
showMusic.value = true;
|
showMusic.value = true;
|
||||||
recommendItem.value = item;
|
recommendItem.value = item;
|
||||||
const { data } = await getListDetail(item.id);
|
const { data } = await getListDetail(item.id);
|
||||||
listDetail.value = data;
|
listDetail.value = data;
|
||||||
|
listLoading.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const listTitle = ref(route.query.type || '歌单列表');
|
const listTitle = ref(route.query.type || '歌单列表');
|
||||||
|
|
||||||
|
const loading = ref(false);
|
||||||
const loadList = async (type: string) => {
|
const loadList = async (type: string) => {
|
||||||
|
loading.value = true;
|
||||||
const params = {
|
const params = {
|
||||||
cat: type || '',
|
cat: type || '',
|
||||||
limit: 30,
|
limit: 30,
|
||||||
@@ -36,6 +41,7 @@ const loadList = async (type: string) => {
|
|||||||
};
|
};
|
||||||
const { data } = await getListByCat(params);
|
const { data } = await getListByCat(params);
|
||||||
recommendList.value = data.playlists;
|
recommendList.value = data.playlists;
|
||||||
|
loading.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (route.query.type) {
|
if (route.query.type) {
|
||||||
@@ -51,6 +57,7 @@ watch(
|
|||||||
async (newParams) => {
|
async (newParams) => {
|
||||||
if (newParams.type) {
|
if (newParams.type) {
|
||||||
recommendList.value = null;
|
recommendList.value = null;
|
||||||
|
listTitle.value = newParams.type || '歌单列表';
|
||||||
loadList(newParams.type as string);
|
loadList(newParams.type as string);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -62,7 +69,7 @@ watch(
|
|||||||
<div class="recommend-title" :class="setAnimationClass('animate__bounceInLeft')">{{ listTitle }}</div>
|
<div class="recommend-title" :class="setAnimationClass('animate__bounceInLeft')">{{ listTitle }}</div>
|
||||||
<!-- 歌单列表 -->
|
<!-- 歌单列表 -->
|
||||||
<n-scrollbar class="recommend" :size="100" @click="showMusic = false">
|
<n-scrollbar class="recommend" :size="100" @click="showMusic = false">
|
||||||
<div v-if="recommendList" class="recommend-list">
|
<div v-loading="loading" class="recommend-list">
|
||||||
<div
|
<div
|
||||||
v-for="(item, index) in recommendList"
|
v-for="(item, index) in recommendList"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
@@ -91,6 +98,7 @@ watch(
|
|||||||
</n-scrollbar>
|
</n-scrollbar>
|
||||||
<music-list
|
<music-list
|
||||||
v-model:show="showMusic"
|
v-model:show="showMusic"
|
||||||
|
v-model:loading="listLoading"
|
||||||
:name="recommendItem?.name || ''"
|
:name="recommendItem?.name || ''"
|
||||||
:song-list="listDetail?.playlist.tracks || []"
|
:song-list="listDetail?.playlist.tracks || []"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -70,6 +70,14 @@ const timerIsQr = (key: string) => {
|
|||||||
return timer;
|
return timer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 离开页面时
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (timerRef.value) {
|
||||||
|
clearInterval(timerRef.value);
|
||||||
|
timerRef.value = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 是否扫码登陆
|
// 是否扫码登陆
|
||||||
const isQr = ref(!isMobile.value);
|
const isQr = ref(!isMobile.value);
|
||||||
const chooseQr = () => {
|
const chooseQr = () => {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<h2>推荐MV</h2>
|
<h2>推荐MV</h2>
|
||||||
</div>
|
</div>
|
||||||
<n-scrollbar :size="100">
|
<n-scrollbar :size="100">
|
||||||
<div class="mv-list-content" :class="setAnimationClass('animate__bounceInLeft')">
|
<div v-loading="loading" class="mv-list-content" :class="setAnimationClass('animate__bounceInLeft')">
|
||||||
<div
|
<div
|
||||||
v-for="(item, index) in mvList"
|
v-for="(item, index) in mvList"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
</n-scrollbar>
|
</n-scrollbar>
|
||||||
|
|
||||||
<n-drawer :show="showMv" height="100vh" placement="bottom" :z-index="999999999">
|
<n-drawer :show="showMv" height="100vh" placement="bottom" :z-index="999999999">
|
||||||
<div class="mv-detail">
|
<div v-loading="mvLoading" class="mv-detail">
|
||||||
<video :src="playMvUrl" controls autoplay></video>
|
<video :src="playMvUrl" controls autoplay></video>
|
||||||
<div class="mv-detail-title">
|
<div class="mv-detail-title">
|
||||||
<div class="title">{{ playMvItem?.name }}</div>
|
<div class="title">{{ playMvItem?.name }}</div>
|
||||||
@@ -62,19 +62,25 @@ const mvList = ref<Array<IMvItem>>([]);
|
|||||||
const playMvItem = ref<IMvItem>();
|
const playMvItem = ref<IMvItem>();
|
||||||
const playMvUrl = ref<string>();
|
const playMvUrl = ref<string>();
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
loading.value = true;
|
||||||
const res = await getTopMv(30);
|
const res = await getTopMv(30);
|
||||||
mvList.value = res.data.data;
|
mvList.value = res.data.data;
|
||||||
|
loading.value = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const mvLoading = ref(false);
|
||||||
const handleShowMv = async (item: IMvItem) => {
|
const handleShowMv = async (item: IMvItem) => {
|
||||||
|
mvLoading.value = true;
|
||||||
store.commit('setIsPlay', false);
|
store.commit('setIsPlay', false);
|
||||||
store.commit('setPlayMusic', false);
|
store.commit('setPlayMusic', false);
|
||||||
showMv.value = true;
|
showMv.value = true;
|
||||||
const res = await getMvUrl(item.id);
|
const res = await getMvUrl(item.id);
|
||||||
playMvItem.value = item;
|
playMvItem.value = item;
|
||||||
playMvUrl.value = res.data.data.url;
|
playMvUrl.value = res.data.data.url;
|
||||||
|
mvLoading.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const close = () => {
|
const close = () => {
|
||||||
|
|||||||
+22
-24
@@ -29,32 +29,30 @@
|
|||||||
:native-scrollbar="false"
|
:native-scrollbar="false"
|
||||||
>
|
>
|
||||||
<div class="title">{{ hotKeyword }}</div>
|
<div class="title">{{ hotKeyword }}</div>
|
||||||
<n-spin :show="searchDetailLoading">
|
<div v-loading="searchDetailLoading" class="search-list-box">
|
||||||
<div class="search-list-box">
|
<template v-if="searchDetail">
|
||||||
<template v-if="searchDetail">
|
<div
|
||||||
<div
|
v-for="(item, index) in searchDetail?.songs"
|
||||||
v-for="(item, index) in searchDetail?.songs"
|
:key="item.id"
|
||||||
:key="item.id"
|
:class="setAnimationClass('animate__bounceInRight')"
|
||||||
:class="setAnimationClass('animate__bounceInRight')"
|
:style="setAnimationDelay(index, 50)"
|
||||||
:style="setAnimationDelay(index, 50)"
|
>
|
||||||
>
|
<song-item :item="item" @play="handlePlay" />
|
||||||
<song-item :item="item" @play="handlePlay" />
|
</div>
|
||||||
</div>
|
<template v-for="(list, key) in searchDetail">
|
||||||
<template v-for="(list, key) in searchDetail">
|
<template v-if="key.toString() !== 'songs'">
|
||||||
<template v-if="key.toString() !== 'songs'">
|
<div
|
||||||
<div
|
v-for="(item, index) in list"
|
||||||
v-for="(item, index) in list"
|
:key="item.id"
|
||||||
:key="item.id"
|
:class="setAnimationClass('animate__bounceInRight')"
|
||||||
:class="setAnimationClass('animate__bounceInRight')"
|
:style="setAnimationDelay(index, 50)"
|
||||||
:style="setAnimationDelay(index, 50)"
|
>
|
||||||
>
|
<SearchItem :item="item" />
|
||||||
<SearchItem :item="item" />
|
</div>
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</template>
|
||||||
</n-spin>
|
</div>
|
||||||
</n-layout>
|
</n-layout>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ const router = useRouter();
|
|||||||
const userDetail = ref<IUserDetail>();
|
const userDetail = ref<IUserDetail>();
|
||||||
const playList = ref<any[]>([]);
|
const playList = ref<any[]>([]);
|
||||||
const recordList = ref();
|
const recordList = ref();
|
||||||
|
const infoLoading = ref(false);
|
||||||
|
|
||||||
const user = computed(() => store.state.user);
|
const user = computed(() => store.state.user);
|
||||||
|
|
||||||
@@ -29,6 +30,7 @@ const loadPage = async () => {
|
|||||||
router.push('/login');
|
router.push('/login');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
infoLoading.value = true;
|
||||||
|
|
||||||
const { data: userData } = await getUserDetail(user.value.userId);
|
const { data: userData } = await getUserDetail(user.value.userId);
|
||||||
userDetail.value = userData;
|
userDetail.value = userData;
|
||||||
@@ -36,9 +38,12 @@ const loadPage = async () => {
|
|||||||
const { data: playlistData } = await getUserPlaylist(user.value.userId);
|
const { data: playlistData } = await getUserPlaylist(user.value.userId);
|
||||||
playList.value = playlistData.playlist;
|
playList.value = playlistData.playlist;
|
||||||
|
|
||||||
getUserRecord(user.value.userId).then(({ data: recordData }) => {
|
// getUserRecord(user.value.userId).then(({ data: recordData }) => {
|
||||||
recordList.value = recordData.allData;
|
// recordList.value = recordData.allData;
|
||||||
});
|
// });
|
||||||
|
const { data: recordData } = await getUserRecord(user.value.userId);
|
||||||
|
recordList.value = recordData.allData;
|
||||||
|
infoLoading.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
@@ -109,7 +114,7 @@ const handlePlay = () => {
|
|||||||
|
|
||||||
<div class="play-list" :class="setAnimationClass('animate__fadeInLeft')">
|
<div class="play-list" :class="setAnimationClass('animate__fadeInLeft')">
|
||||||
<div class=" ">创建的歌单</div>
|
<div class=" ">创建的歌单</div>
|
||||||
<n-scrollbar>
|
<n-scrollbar v-loading="infoLoading">
|
||||||
<div v-for="(item, index) in playList" :key="index" class="play-list-item" @click="showPlaylist(item.id)">
|
<div v-for="(item, index) in playList" :key="index" class="play-list-item" @click="showPlaylist(item.id)">
|
||||||
<n-image :src="getImgUrl(item.coverImgUrl, '50y50')" class="play-list-item-img" lazy preview-disabled />
|
<n-image :src="getImgUrl(item.coverImgUrl, '50y50')" class="play-list-item-img" lazy preview-disabled />
|
||||||
<div class="play-list-item-info">
|
<div class="play-list-item-info">
|
||||||
@@ -125,7 +130,7 @@ const handlePlay = () => {
|
|||||||
<div v-if="!isMobile" class="right" :class="setAnimationClass('animate__fadeInRight')">
|
<div v-if="!isMobile" class="right" :class="setAnimationClass('animate__fadeInRight')">
|
||||||
<div class="title">听歌排行</div>
|
<div class="title">听歌排行</div>
|
||||||
<div class="record-list">
|
<div class="record-list">
|
||||||
<n-scrollbar>
|
<n-scrollbar v-loading="infoLoading">
|
||||||
<div
|
<div
|
||||||
v-for="(item, index) in recordList"
|
v-for="(item, index) in recordList"
|
||||||
:key="item.song.id"
|
:key="item.song.id"
|
||||||
|
|||||||
Reference in New Issue
Block a user