feat: 添加eslint 和 桌面歌词(未完成)

This commit is contained in:
alger
2024-05-16 18:54:30 +08:00
parent 5e8676a039
commit a9e5bb33e4
65 changed files with 2724 additions and 2320 deletions
+23 -24
View File
@@ -8,13 +8,9 @@
</div>
</div>
<div class="app-menu-list">
<div class="app-menu-item" v-for="(item,index) in menus">
<div v-for="(item, index) in menus" :key="item.path" class="app-menu-item">
<router-link class="app-menu-item-link" :to="item.path">
<i
class="iconfont app-menu-item-icon"
:style="iconStyle(index)"
:class="item.meta.icon"
></i>
<i class="iconfont app-menu-item-icon" :style="iconStyle(index)" :class="item.meta.icon"></i>
<span v-if="isText" class="app-menu-item-text ml-3">{{ item.meta.title }}</span>
</router-link>
</div>
@@ -24,44 +20,47 @@
</template>
<script lang="ts" setup>
import { useRoute } from "vue-router";
import { useRoute } from 'vue-router';
const props = defineProps({
isText: {
type: Boolean,
default: false
default: false,
},
size: {
type: String,
default: '26px'
default: '26px',
},
color: {
type: String,
default: '#aaa'
default: '#aaa',
},
selectColor: {
type: String,
default: '#10B981'
default: '#10B981',
},
menus: {
type: Array as any,
default: []
}
})
default: () => [],
},
});
const route = useRoute();
const path = ref(route.path);
watch(() => route.path, async newParams => {
path.value = newParams
})
watch(
() => route.path,
async (newParams) => {
path.value = newParams;
},
);
const iconStyle = (index: any) => {
let style = {
const style = {
fontSize: props.size,
color: path.value === props.menus[index].path ? props.selectColor : props.color
}
return style
}
color: path.value === props.menus[index].path ? props.selectColor : props.color,
};
return style;
};
</script>
<style lang="scss" scoped>
@@ -83,4 +82,4 @@ const iconStyle = (index: any) => {
transform: scale(1.05);
transition: 0.2s ease-in-out;
}
</style>
</style>
+46 -53
View File
@@ -1,33 +1,25 @@
<template>
<n-drawer
:show="musicFull"
height="100vh"
placement="bottom"
:drawer-style="{ backgroundColor: 'transparent' }"
>
<n-drawer :show="musicFull" height="100vh" placement="bottom" :drawer-style="{ backgroundColor: 'transparent' }">
<div id="drawer-target">
<div class="drawer-back" :class="{'paused': !isPlaying}" :style="{backgroundImage:`url(${getImgUrl(playMusic?.picUrl, '300y300')})`}"></div>
<div
class="drawer-back"
:class="{ paused: !isPlaying }"
:style="{ backgroundImage: `url(${getImgUrl(playMusic?.picUrl, '300y300')})` }"
></div>
<div class="music-img">
<n-image
ref="PicImgRef"
:src="getImgUrl(playMusic?.picUrl, '300y300')"
class="img"
lazy
preview-disabled
/>
<n-image ref="PicImgRef" :src="getImgUrl(playMusic?.picUrl, '300y300')" class="img" lazy preview-disabled />
</div>
<div class="music-content">
<div class="music-content-name">{{ playMusic.song.name }}</div>
<div class="music-content-singer">
<span v-for="(item, index) in playMusic.song.artists" :key="index">
{{ item.name
}}{{ index < playMusic.song.artists.length - 1 ? ' / ' : '' }}
{{ item.name }}{{ index < playMusic.song.artists.length - 1 ? ' / ' : '' }}
</span>
</div>
<n-layout
ref="lrcSider"
class="music-lrc"
style="height: 55vh"
ref="lrcSider"
:native-scrollbar="false"
@mouseover="mouseOverLayout"
@mouseleave="mouseLeaveLayout"
@@ -38,7 +30,8 @@
:class="{ 'now-text': isCurrentLrc(index, nowTime) }"
@click="setAudioTime(index, audio)"
>
{{ item.text }}
<div>{{ item.text }}</div>
<div class="music-lrc-text-tr">{{ item.trText }}</div>
</div>
</template>
</n-layout>
@@ -53,20 +46,21 @@
</template>
<script setup lang="ts">
import type { SongResult } from '@/type/music'
import { getImgUrl } from '@/utils'
import { useStore } from 'vuex'
import { useStore } from 'vuex';
import {
addCorrectionTime,
isCurrentLrc,
lrcArray,
newLrcIndex,
isCurrentLrc,
addCorrectionTime,
nowTime,
reduceCorrectionTime,
setAudioTime,
nowTime,
} from '@/hooks/MusicHook'
} from '@/hooks/MusicHook';
import type { SongResult } from '@/type/music';
import { getImgUrl } from '@/utils';
const store = useStore()
const store = useStore();
const props = defineProps({
musicFull: {
@@ -77,39 +71,36 @@ const props = defineProps({
type: HTMLAudioElement,
default: null,
},
})
const emit = defineEmits(['update:musicFull'])
});
// 播放的音乐信息
const playMusic = computed(() => store.state.playMusic as SongResult)
const isPlaying = computed(() => store.state.play as boolean)
const playMusic = computed(() => store.state.playMusic as SongResult);
const isPlaying = computed(() => store.state.play as boolean);
// 获取歌词滚动dom
const lrcSider = ref<any>(null)
const isMouse = ref(false)
const lrcSider = ref<any>(null);
const isMouse = ref(false);
// 歌词滚动方法
const lrcScroll = () => {
if (props.musicFull && !isMouse.value) {
let top = newLrcIndex.value * 50 - 225
lrcSider.value.scrollTo({ top: top, behavior: 'smooth' })
const top = newLrcIndex.value * 60 - 225;
lrcSider.value.scrollTo({ top, behavior: 'smooth' });
}
}
};
const mouseOverLayout = () => {
isMouse.value = true
}
isMouse.value = true;
};
const mouseLeaveLayout = () => {
setTimeout(() => {
isMouse.value = false
}, 3000)
}
isMouse.value = false;
}, 3000);
};
defineExpose({
lrcScroll,
})
});
</script>
<style scoped lang="scss">
@keyframes round {
0% {
transform: rotate(0deg);
@@ -118,7 +109,7 @@ defineExpose({
transform: rotate(360deg);
}
}
.drawer-back{
.drawer-back {
@apply absolute bg-cover bg-center opacity-70;
filter: blur(80px) brightness(80%);
z-index: -1;
@@ -161,28 +152,30 @@ defineExpose({
}
}
.music-content-time{
.music-content-time {
display: none;
@apply flex justify-center items-center;
@apply flex justify-center items-center;
}
.music-lrc {
background-color: inherit;
width: 500px;
height: 550px;
.now-text {
@apply text-red-500;
}
&-text {
@apply text-white text-lg flex justify-center items-center cursor-pointer;
height: 50px;
@apply text-white text-lg flex flex-col justify-center items-center cursor-pointer font-bold;
height: 60px;
transition: all 0.2s ease-out;
&:hover {
@apply font-bold text-xl text-red-500;
@apply font-bold text-red-500;
}
}
.now-text {
@apply font-bold text-xl text-red-500;
&-tr {
@apply text-sm font-normal;
}
}
}
}
+73 -92
View File
@@ -1,6 +1,6 @@
<template>
<!-- 展开全屏 -->
<music-full ref="MusicFullRef" v-model:musicFull="musicFull" :audio="(audio.value as HTMLAudioElement)" />
<music-full ref="MusicFullRef" v-model:musicFull="musicFull" :audio="audio.value as HTMLAudioElement" />
<!-- 底部播放栏 -->
<div class="music-play-bar" :class="setAnimationClass('animate__bounceInUp')">
<n-image
@@ -19,8 +19,7 @@
<div class="music-content-name">
<n-ellipsis class="text-ellipsis" line-clamp="1">
<span v-for="(item, index) in playMusic.song.artists" :key="index">
{{ item.name
}}{{ index < playMusic.song.artists.length - 1 ? ' / ' : '' }}
{{ item.name }}{{ index < playMusic.song.artists.length - 1 ? ' / ' : '' }}
</span>
</n-ellipsis>
</div>
@@ -38,22 +37,14 @@
</div>
<div class="music-time">
<div class="time">{{ getNowTime }}</div>
<n-slider
v-model:value="timeSlider"
:step="0.05"
:tooltip="false"
></n-slider>
<n-slider v-model:value="timeSlider" :step="0.05" :tooltip="false"></n-slider>
<div class="time">{{ getAllTime }}</div>
</div>
<div class="audio-volume">
<div>
<i class="iconfont icon-notificationfill"></i>
</div>
<n-slider
v-model:value="volumeSlider"
:step="0.01"
:tooltip="false"
></n-slider>
<n-slider v-model:value="volumeSlider" :step="0.01" :tooltip="false"></n-slider>
</div>
<div class="audio-button">
<!-- <n-tooltip trigger="hover" :z-index="9999999">
@@ -68,12 +59,12 @@
</template>
解析播放
</n-tooltip> -->
<!-- <n-tooltip trigger="hover" :z-index="9999999">
<n-tooltip trigger="hover" :z-index="9999999">
<template #trigger>
<i class="iconfont icon-full" @click="setMusicFull"></i>
<i class="iconfont ri-netease-cloud-music-line" @click="openLyric"></i>
</template>
歌词
</n-tooltip> -->
</n-tooltip>
<n-popover trigger="click" :z-index="99999999" content-class="music-play" raw :show-arrow="false" :delay="200">
<template #trigger>
<n-tooltip trigger="manual" :z-index="9999999">
@@ -87,154 +78,143 @@
<div class="music-play-list-back"></div>
<n-scrollbar>
<div class="music-play-list-content">
<song-item v-for="(item, index) in playList" :key="item.id" :item="item" mini></song-item>
<song-item v-for="item in playList" :key="item.id" :item="item" mini></song-item>
</div>
</n-scrollbar>
</div>
</n-popover>
</div>
<!-- 播放音乐 -->
</div>
</template>
<script lang="ts" setup>
import type { SongResult } from '@/type/music'
import { secondToMinute, getImgUrl } from '@/utils'
import { useStore } from 'vuex'
import { setAnimationClass } from '@/utils'
import {
loadLrc,
nowTime,
allTime
} from '@/hooks/MusicHook'
import MusicFull from './MusicFull.vue'
import SongItem from '@/components/common/SongItem.vue'
import { useStore } from 'vuex';
const store = useStore()
import SongItem from '@/components/common/SongItem.vue';
import { allTime, loadLrc, nowTime, openLyric, sendLyricToWin } from '@/hooks/MusicHook';
import type { SongResult } from '@/type/music';
import { getImgUrl, secondToMinute, setAnimationClass } from '@/utils';
import MusicFull from './MusicFull.vue';
const store = useStore();
// 播放的音乐信息
const playMusic = computed(() => store.state.playMusic as SongResult)
const playMusic = computed(() => store.state.playMusic as SongResult);
// 是否播放
const play = computed(() => store.state.play as boolean)
const play = computed(() => store.state.play as boolean);
const playList = computed(() => store.state.playList as SongResult[])
const playList = computed(() => store.state.playList as SongResult[]);
const audio = {
value: document.querySelector('#MusicAudio') as HTMLAudioElement
}
value: document.querySelector('#MusicAudio') as HTMLAudioElement,
};
watch(
() => store.state.playMusicUrl,
() => {
loadLrc(playMusic.value.id)
loadLrc(playMusic.value.id);
},
{ immediate: true }
)
{ immediate: true },
);
const audioPlay = () => {
if (audio.value) {
audio.value.play()
audio.value.play();
}
}
const audioPause = () => {
if (audio.value) {
audio.value.pause()
}
}
};
// 计算属性 获取当前播放时间的进度
const timeSlider = computed({
get: () => (nowTime.value / allTime.value) * 100,
set: (value) => {
if (!audio.value) return
audio.value.currentTime = (value * allTime.value) / 100
audioPlay()
store.commit('setPlayMusic', true)
if (!audio.value) return;
audio.value.currentTime = (value * allTime.value) / 100;
audioPlay();
store.commit('setPlayMusic', true);
},
})
});
// 音量条
const audioVolume = ref(1)
const audioVolume = ref(1);
const volumeSlider = computed({
get: () => audioVolume.value * 100,
set: (value) => {
if(!audio.value) return
audio.value.volume = value / 100
if (!audio.value) return;
audio.value.volume = value / 100;
},
})
});
// 获取当前播放时间
const getNowTime = computed(() => {
return secondToMinute(nowTime.value)
})
return secondToMinute(nowTime.value);
});
// 获取总时间
const getAllTime = computed(() => {
return secondToMinute(allTime.value)
})
return secondToMinute(allTime.value);
});
// 监听音乐播放 获取时间
const onAudio = () => {
if(audio.value){
audio.value.removeEventListener('timeupdate', handleGetAudioTime)
audio.value.removeEventListener('ended', handleEnded)
audio.value.addEventListener('timeupdate', handleGetAudioTime)
audio.value.addEventListener('ended', handleEnded)
if (audio.value) {
audio.value.removeEventListener('timeupdate', handleGetAudioTime);
audio.value.removeEventListener('ended', handleEnded);
audio.value.addEventListener('timeupdate', handleGetAudioTime);
audio.value.addEventListener('ended', handleEnded);
// 监听音乐播放暂停
audio.value.addEventListener('pause', () => {
store.commit('setPlayMusic', false)
})
store.commit('setPlayMusic', false);
});
audio.value.addEventListener('play', () => {
store.commit('setPlayMusic', true)
})
store.commit('setPlayMusic', true);
});
}
}
};
onAudio()
onAudio();
function handleEnded() {
store.commit('nextPlay')
store.commit('nextPlay');
}
function handlePrev() {
store.commit('prevPlay')
store.commit('prevPlay');
}
const MusicFullRef = ref<any>(null)
const MusicFullRef = ref<any>(null);
function handleGetAudioTime(this: any) {
// 监听音频播放的实时时间事件
const audio = this as HTMLAudioElement
const audio = this as HTMLAudioElement;
// 获取当前播放时间
nowTime.value = Math.floor(audio.currentTime)
nowTime.value = Math.floor(audio.currentTime);
// 获取总时间
allTime.value = audio.duration
allTime.value = audio.duration;
// 获取音量
audioVolume.value = audio.volume
MusicFullRef.value?.lrcScroll()
audioVolume.value = audio.volume;
sendLyricToWin(store.state.isPlay);
MusicFullRef.value?.lrcScroll();
}
// 播放暂停按钮事件
const playMusicEvent = async () => {
if (play.value) {
store.commit('setPlayMusic', false)
store.commit('setPlayMusic', false);
} else {
store.commit('setPlayMusic', true)
store.commit('setPlayMusic', true);
}
}
};
const musicFull = ref(false)
const musicFull = ref(false);
// 设置musicFull
const setMusicFull = () => {
musicFull.value = !musicFull.value
}
musicFull.value = !musicFull.value;
};
</script>
<style lang="scss" scoped>
.text-ellipsis {
width: 100%;
}
@@ -243,7 +223,9 @@ const setMusicFull = () => {
@apply h-20 w-full absolute bottom-0 left-0 flex items-center rounded-t-2xl overflow-hidden box-border px-6 py-2;
z-index: 9999;
box-shadow: 0px 0px 10px 2px rgba(203, 203, 203, 0.034);
background-color: rgba(0, 0, 0, 0.747); .music-content {
background-color: rgba(0, 0, 0, 0.747);
animation-duration: 0.5s !important;
.music-content {
width: 140px;
@apply ml-4;
@@ -310,16 +292,15 @@ const setMusicFull = () => {
}
}
.music-play{
&-list{
.music-play {
&-list {
height: 50vh;
@apply relative rounded-3xl overflow-hidden;
&-back{
&-back {
backdrop-filter: blur(20px);
@apply absolute top-0 left-0 w-full h-full bg-gray-800 bg-opacity-75;
}
&-content{
&-content {
padding: 10px;
}
}
+161 -168
View File
@@ -1,168 +1,161 @@
<template>
<div class="search-box flex">
<div class="search-box-input flex-1">
<n-input
size="medium"
round
v-model:value="searchValue"
:placeholder="hotSearchKeyword"
class="border border-gray-600"
@keydown.enter="search"
>
<template #prefix>
<i class="iconfont icon-search"></i>
</template>
<template #suffix>
<div class="w-20 px-3 flex justify-between items-center">
<div>{{ searchTypeOptions.find(item => item.key === searchType)?.label }}</div>
<n-dropdown trigger="hover" @select="selectSearchType" :options="searchTypeOptions">
<i class="iconfont icon-xiasanjiaoxing"></i>
</n-dropdown>
</div>
</template>
</n-input>
</div>
<div class="user-box">
<n-dropdown trigger="hover" @select="selectItem" :options="userSetOptions">
<i class="iconfont icon-xiasanjiaoxing"></i>
</n-dropdown>
<n-avatar
class="ml-2 cursor-pointer"
circle
size="medium"
:src="getImgUrl(store.state.user.avatarUrl)"
v-if="store.state.user"
/>
<div class="mx-2 rounded-full cursor-pointer text-sm" v-else @click="toLogin">登录</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { getSearchKeyword } from '@/api/home';
import { getUserDetail, logout } from '@/api/login';
import { useRouter } from 'vue-router';
import { useStore } from 'vuex';
import request from '@/utils/request_mt'
import { getImgUrl } from '@/utils';
import {USER_SET_OPTIONS, SEARCH_TYPES} from '@/const/bar-const'
const router = useRouter()
const store = useStore();
const userSetOptions = ref(USER_SET_OPTIONS)
// 推荐热搜词
const hotSearchKeyword = ref("搜索点什么吧...")
const hotSearchValue = ref("")
const loadHotSearchKeyword = async () => {
const { data } = await getSearchKeyword();
hotSearchKeyword.value = data.data.showKeyword
hotSearchValue.value = data.data.realkeyword
}
const loadPage = async () => {
const token = localStorage.getItem("token")
if (!token) return
const { data } = await getUserDetail()
store.state.user = data.profile
localStorage.setItem('user', JSON.stringify(data.profile))
}
watchEffect(() => {
loadPage()
if (store.state.user) {
userSetOptions.value = USER_SET_OPTIONS
} else {
userSetOptions.value = USER_SET_OPTIONS.filter(item => item.key !== 'logout')
}
})
const toLogin = () => {
router.push('/login')
}
// 页面初始化
onMounted(() => {
loadHotSearchKeyword()
loadPage()
})
// 搜索词
const searchValue = ref("")
const searchType = ref(1)
const search = () => {
let value = searchValue.value
if (value == "") {
searchValue.value = hotSearchValue.value
} else {
router.push({
path: "/search",
query: {
keyword: value,
type: searchType.value
}
})
}
}
const selectSearchType = (key: any) => {
searchType.value = key
}
const searchTypeOptions = ref(SEARCH_TYPES)
const selectItem = async (key: any) => {
// switch 判断
switch (key) {
case 'card':
await request.get('/?do=sign')
.then(res => {
console.log(res)
})
break;
case 'card_music':
await request.get('/?do=daka')
.then(res => {
console.log(res)
})
break;
case 'listen':
await request.get('/?do=listen&id=1885175990&time=300')
.then(res => {
console.log(res)
})
break;
case 'logout':
logout().then(() => {
store.state.user = null
localStorage.clear()
})
break;
case 'login':
router.push("/login")
break;
case 'set':
router.push("/set")
break;
}
}
</script>
<style lang="scss" scoped>
.user-box {
@apply ml-4 flex text-lg justify-center items-center rounded-full pl-3 border border-gray-600;
background: #1a1a1a;
}
.search-box{
@apply pb-4 pr-4;
}
.search-box-input {
@apply relative;
}
</style>
<template>
<div class="search-box flex">
<div class="search-box-input flex-1">
<n-input
v-model:value="searchValue"
size="medium"
round
:placeholder="hotSearchKeyword"
class="border border-gray-600"
@keydown.enter="search"
>
<template #prefix>
<i class="iconfont icon-search"></i>
</template>
<template #suffix>
<div class="w-20 px-3 flex justify-between items-center">
<div>{{ searchTypeOptions.find((item) => item.key === searchType)?.label }}</div>
<n-dropdown trigger="hover" :options="searchTypeOptions" @select="selectSearchType">
<i class="iconfont icon-xiasanjiaoxing"></i>
</n-dropdown>
</div>
</template>
</n-input>
</div>
<div class="user-box">
<n-dropdown trigger="hover" :options="userSetOptions" @select="selectItem">
<i class="iconfont icon-xiasanjiaoxing"></i>
</n-dropdown>
<n-avatar
v-if="store.state.user"
class="ml-2 cursor-pointer"
circle
size="medium"
:src="getImgUrl(store.state.user.avatarUrl)"
/>
<div v-else class="mx-2 rounded-full cursor-pointer text-sm" @click="toLogin">登录</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { useRouter } from 'vue-router';
import { useStore } from 'vuex';
import { getSearchKeyword } from '@/api/home';
import { getUserDetail, logout } from '@/api/login';
import { SEARCH_TYPES, USER_SET_OPTIONS } from '@/const/bar-const';
import { getImgUrl } from '@/utils';
import request from '@/utils/request_mt';
const router = useRouter();
const store = useStore();
const userSetOptions = ref(USER_SET_OPTIONS);
// 推荐热搜词
const hotSearchKeyword = ref('搜索点什么吧...');
const hotSearchValue = ref('');
const loadHotSearchKeyword = async () => {
const { data } = await getSearchKeyword();
hotSearchKeyword.value = data.data.showKeyword;
hotSearchValue.value = data.data.realkeyword;
};
const loadPage = async () => {
const token = localStorage.getItem('token');
if (!token) return;
const { data } = await getUserDetail();
store.state.user = data.profile;
localStorage.setItem('user', JSON.stringify(data.profile));
};
watchEffect(() => {
loadPage();
if (store.state.user) {
userSetOptions.value = USER_SET_OPTIONS;
} else {
userSetOptions.value = USER_SET_OPTIONS.filter((item) => item.key !== 'logout');
}
});
const toLogin = () => {
router.push('/login');
};
// 页面初始化
onMounted(() => {
loadHotSearchKeyword();
loadPage();
});
// 搜索词
const searchValue = ref('');
const searchType = ref(1);
const search = () => {
const { value } = searchValue;
if (value === '') {
searchValue.value = hotSearchValue.value;
} else {
router.push({
path: '/search',
query: {
keyword: value,
type: searchType.value,
},
});
}
};
const selectSearchType = (key: any) => {
searchType.value = key;
};
const searchTypeOptions = ref(SEARCH_TYPES);
const selectItem = async (key: any) => {
// switch 判断
switch (key) {
case 'card':
await request.get('/?do=sign').then((res) => {
console.log(res);
});
break;
case 'card_music':
await request.get('/?do=daka').then((res) => {
console.log(res);
});
break;
case 'listen':
await request.get('/?do=listen&id=1885175990&time=300').then((res) => {
console.log(res);
});
break;
case 'logout':
logout().then(() => {
store.state.user = null;
localStorage.clear();
});
break;
case 'login':
router.push('/login');
break;
case 'set':
router.push('/set');
break;
default:
}
};
</script>
<style lang="scss" scoped>
.user-box {
@apply ml-4 flex text-lg justify-center items-center rounded-full pl-3 border border-gray-600;
background: #1a1a1a;
}
.search-box {
@apply pb-4 pr-4;
}
.search-box-input {
@apply relative;
}
</style>
+12 -19
View File
@@ -5,9 +5,6 @@
<button @click="minimize">
<i class="iconfont icon-minisize"></i>
</button>
<!-- <button @click="maximize">
<i class="iconfont icon-maxsize"></i>
</button> -->
<button @click="close">
<i class="iconfont icon-close"></i>
</button>
@@ -16,18 +13,14 @@
</template>
<script setup lang="ts">
import { useDialog } from 'naive-ui'
import { useDialog } from 'naive-ui';
const dialog = useDialog()
const windowData = window as any
const dialog = useDialog();
const windowData = window as any;
const minimize = () => {
windowData.electronAPI.minimize()
}
const maximize = () => {
windowData.electronAPI.maximize()
}
windowData.electronAPI.minimize();
};
const close = () => {
dialog.warning({
@@ -36,17 +29,17 @@ const close = () => {
positiveText: '最小化',
negativeText: '关闭',
onPositiveClick: () => {
windowData.electronAPI.miniTray()
windowData.electronAPI.miniTray();
},
onNegativeClick: () => {
windowData.electronAPI.close()
}
})
}
windowData.electronAPI.close();
},
});
};
const drag = (event: MouseEvent) => {
windowData.electronAPI.dragStart(event)
}
windowData.electronAPI.dragStart(event);
};
</script>
<style scoped lang="scss">
+3 -3
View File
@@ -1,5 +1,5 @@
import AppMenu from "./AppMenu.vue";
import PlayBar from "./PlayBar.vue";
import SearchBar from "./SearchBar.vue";
import AppMenu from './AppMenu.vue';
import PlayBar from './PlayBar.vue';
import SearchBar from './SearchBar.vue';
export { AppMenu, PlayBar, SearchBar };
+6 -6
View File
@@ -5,20 +5,20 @@
</template>
<script setup lang="ts">
const props = defineProps({
defineProps({
lrcList: {
type: Array,
default: () => []
default: () => [],
},
lrcIndex: {
type: Number,
default: 0
default: 0,
},
lrcTime: {
type: Number,
default: 0
default: 0,
},
})
});
</script>
<style scoped lang="scss"></style>
<style scoped lang="scss"></style>