Files
AlgerMusicPlayer/src/layout/components/PlayBar.vue

365 lines
8.8 KiB
Vue
Raw Normal View History

2021-07-21 15:01:39 +08:00
<template>
<!-- 展开全屏 -->
<music-full
ref="MusicFullRef"
v-model:music-full="musicFullVisible"
:audio="audio.value as HTMLAudioElement"
:background="background"
/>
<!-- 底部播放栏 -->
2024-09-12 15:00:00 +08:00
<div
class="music-play-bar"
2024-09-12 16:44:42 +08:00
:class="setAnimationClass('animate__bounceInUp') + ' ' + (musicFullVisible ? 'play-bar-opcity' : '')"
2024-09-12 15:00:00 +08:00
>
<n-image
:src="getImgUrl(playMusic?.picUrl, '300y300')"
class="play-bar-img"
lazy
preview-disabled
@click="setMusicFull"
/>
<div class="music-content">
<div class="music-content-title">
<n-ellipsis class="text-ellipsis" line-clamp="1">
{{ playMusic.name }}
</n-ellipsis>
</div>
<div class="music-content-name">
<n-ellipsis class="text-ellipsis" line-clamp="1">
2024-09-13 09:43:05 +08:00
<span v-for="(item, index) in playMusic.song.artists" :key="index">
{{ item.name }}{{ index < playMusic.song.artists.length - 1 ? ' / ' : '' }}
</span>
</n-ellipsis>
</div>
</div>
<div class="music-buttons">
<div class="music-buttons-prev" @click="handlePrev">
<i class="iconfont icon-prev"></i>
</div>
<div class="music-buttons-play" @click="playMusicEvent">
<i class="iconfont icon" :class="play ? 'icon-stop' : 'icon-play'"></i>
</div>
<div class="music-buttons-next" @click="handleEnded">
<i class="iconfont icon-next"></i>
</div>
</div>
<div class="music-time">
<div class="time">{{ getNowTime }}</div>
<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>
2021-07-21 15:01:39 +08:00
</div>
<div class="audio-button">
<!-- <n-tooltip trigger="hover" :z-index="9999999">
<template #trigger>
<i class="iconfont icon-likefill"></i>
</template>
喜欢
</n-tooltip> -->
<!-- <n-tooltip trigger="hover" :z-index="9999999">
<template #trigger>
<i class="iconfont icon-Play" @click="parsingMusic"></i>
</template>
解析播放
</n-tooltip> -->
2024-09-12 16:44:42 +08:00
<n-tooltip v-if="isElectron" class="music-lyric" trigger="hover" :z-index="9999999">
<template #trigger>
<i class="iconfont ri-netease-cloud-music-line" @click="openLyric"></i>
</template>
歌词
</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">
<template #trigger>
<i class="iconfont icon-list"></i>
</template>
播放列表
</n-tooltip>
</template>
<div class="music-play-list">
<div class="music-play-list-back"></div>
<n-virtual-list :item-size="57" item-resizable :items="playList">
<template #default="{ item }">
<div class="music-play-list-content">
<song-item :key="item.id" :item="item" mini></song-item>
</div>
</template>
2024-09-12 16:44:42 +08:00
</n-virtual-list>
</div>
</n-popover>
</div>
<!-- 播放音乐 -->
</div>
2021-07-21 15:01:39 +08:00
</template>
<script lang="ts" setup>
import { useStore } from 'vuex';
import SongItem from '@/components/common/SongItem.vue';
2024-09-12 16:44:42 +08:00
import { allTime, isElectron, loadLrc, nowTime, openLyric, sendLyricToWin } from '@/hooks/MusicHook';
2024-09-13 09:43:05 +08:00
import type { SongResult } from '@/type/music';
import { getImgUrl, secondToMinute, setAnimationClass } from '@/utils';
import { getImageLinearBackground } from '@/utils/linearColor';
import MusicFull from './MusicFull.vue';
const store = useStore();
2021-07-21 17:45:21 +08:00
// 播放的音乐信息
2024-09-13 09:43:05 +08:00
const playMusic = computed(() => store.state.playMusic as SongResult);
// 是否播放
const play = computed(() => store.state.play as boolean);
2024-09-13 09:43:05 +08:00
const playList = computed(() => store.state.playList as SongResult[]);
const audio = {
value: document.querySelector('#MusicAudio') as HTMLAudioElement,
};
const background = ref('#000');
watch(
() => store.state.playMusic,
async () => {
loadLrc(playMusic.value.id);
background.value = playMusic.value.backgroundColor as string;
},
{ immediate: true, deep: true },
);
const audioPlay = () => {
if (audio.value) {
audio.value.play();
}
};
// 计算属性 获取当前播放时间的进度
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);
},
});
2021-07-22 11:32:38 +08:00
// 音量条
const audioVolume = ref(1);
2021-07-22 11:32:38 +08:00
const volumeSlider = computed({
get: () => audioVolume.value * 100,
set: (value) => {
if (!audio.value) return;
audio.value.volume = value / 100;
},
});
// 获取当前播放时间
const getNowTime = computed(() => {
return secondToMinute(nowTime.value);
});
2021-07-21 15:01:39 +08:00
// 获取总时间
const getAllTime = computed(() => {
return secondToMinute(allTime.value);
});
2021-09-28 22:40:44 +08:00
// 监听音乐播放 获取时间
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);
// 监听音乐播放暂停
audio.value.addEventListener('pause', () => {
store.commit('setPlayMusic', false);
});
audio.value.addEventListener('play', () => {
store.commit('setPlayMusic', true);
});
}
};
2021-09-28 22:40:44 +08:00
onAudio();
function handleEnded() {
store.commit('nextPlay');
}
function handlePrev() {
store.commit('prevPlay');
}
const MusicFullRef = ref<any>(null);
2024-05-21 11:01:23 +08:00
function handleGetAudioTime(this: HTMLAudioElement) {
// 监听音频播放的实时时间事件
const audio = this as HTMLAudioElement;
// 获取当前播放时间
nowTime.value = Math.floor(audio.currentTime);
// 获取总时间
allTime.value = audio.duration;
// 获取音量
audioVolume.value = audio.volume;
sendLyricToWin(store.state.isPlay);
2024-09-12 16:44:42 +08:00
if (musicFullVisible.value) {
MusicFullRef.value?.lrcScroll();
}
}
2021-07-21 17:45:21 +08:00
// 播放暂停按钮事件
2021-07-21 17:45:21 +08:00
const playMusicEvent = async () => {
if (play.value) {
store.commit('setPlayMusic', false);
} else {
store.commit('setPlayMusic', true);
}
};
2021-07-21 15:01:39 +08:00
2024-09-12 16:44:42 +08:00
const musicFullVisible = ref(false);
2021-07-25 15:08:02 +08:00
// 设置musicFull
const setMusicFull = () => {
2024-09-12 16:44:42 +08:00
musicFullVisible.value = !musicFullVisible.value;
};
2021-07-21 15:01:39 +08:00
</script>
<style lang="scss" scoped>
2021-07-21 17:45:21 +08:00
.text-ellipsis {
width: 100%;
2021-07-21 17:45:21 +08:00
}
2021-07-21 15:01:39 +08:00
.music-play-bar {
@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;
2024-01-02 22:19:39 +08:00
box-shadow: 0px 0px 10px 2px rgba(203, 203, 203, 0.034);
2024-09-12 15:00:00 +08:00
background-color: #212121;
animation-duration: 0.5s !important;
.music-content {
width: 140px;
@apply ml-4;
&-title {
@apply text-base text-white;
}
&-name {
@apply text-xs mt-1;
@apply text-gray-400;
2021-07-25 15:08:02 +08:00
}
}
2021-07-21 15:01:39 +08:00
}
2024-09-12 15:00:00 +08:00
.play-bar-opcity {
background-color: rgba(0, 0, 0, 0.218);
}
2021-07-21 15:01:39 +08:00
.play-bar-img {
@apply w-14 h-14 rounded-2xl;
2021-07-21 15:01:39 +08:00
}
2021-07-21 17:45:21 +08:00
.music-buttons {
@apply mx-6;
.iconfont {
@apply text-2xl hover:text-green-500 transition;
}
.icon {
@apply text-xl hover:text-white;
}
@apply flex items-center;
> div {
@apply cursor-pointer;
}
&-play {
background: #383838;
@apply flex justify-center items-center w-12 h-12 rounded-full mx-4 hover:bg-green-500 transition bg-opacity-40;
}
2021-07-21 17:45:21 +08:00
}
.music-time {
@apply flex flex-1 items-center;
.time {
@apply mx-4 mt-1;
}
2021-07-22 11:32:38 +08:00
}
.audio-volume {
width: 140px;
@apply flex items-center mx-4;
.iconfont {
@apply text-2xl hover:text-green-500 transition cursor-pointer mr-4;
}
2021-07-21 17:45:21 +08:00
}
2021-07-22 17:31:43 +08:00
.audio-button {
@apply flex items-center mx-4;
.iconfont {
@apply text-2xl hover:text-green-500 transition cursor-pointer m-4;
}
2021-07-22 17:31:43 +08:00
}
.music-play {
&-list {
height: 50vh;
width: 300px;
@apply relative rounded-3xl overflow-hidden py-2;
&-back {
backdrop-filter: blur(20px);
@apply absolute top-0 left-0 w-full h-full bg-gray-800 bg-opacity-75;
}
&-content {
@apply mx-2;
}
}
}
.mobile {
.music-play-bar {
@apply px-4;
bottom: 70px;
}
.music-time {
display: none;
}
.ri-netease-cloud-music-line {
display: none;
}
.audio-volume {
display: none;
}
.audio-button {
@apply mx-0;
}
.music-buttons {
@apply m-0;
&-prev,
&-next {
display: none;
}
&-play {
@apply m-0;
}
}
.music-content {
flex: 1;
}
}
:deep(.n-popover) {
box-shadow: none;
}
</style>