捕梦者基础前端框架
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

288 lines
10 KiB

<template>
<ele-card header="音乐播放功能演示">
<div class="demo-music-wrap">
<div class="music-wrapper">
<div
:key="current.vid"
class="music-body"
:style="{ backgroundImage: `url('${current.poster}')` }"
>
<div ref="lrcRef" class="lrc-wrap" style="height: 100%"></div>
<canvas ref="analyzeRef" class="analyze-wrap"></canvas>
</div>
<div class="music-footer">
<div class="music-controls">
<el-icon>
<step-backward-filled @click="playPrev" />
</el-icon>
<el-icon @click="playOrPause">
<pause-filled v-if="playing" style="transform: scale(1.4)" />
<play-filled v-else style="transform: scale(1.4)" />
</el-icon>
<el-icon>
<step-forward-filled @click="playNext" />
</el-icon>
</div>
<ele-xg-player
:key="current.vid"
:config="config"
@player="onPlayer"
style="flex: 1; overflow: visible"
/>
</div>
</div>
</div>
</ele-card>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import type Player from 'xgplayer';
import MusicPreset, { Analyze, Lyric } from 'xgplayer-music';
import {
PlayFilled,
PauseFilled,
StepForwardFilled,
StepBackwardFilled
} from '@/components/icons';
/** 歌词 */
const lyrics = [
{
vid: '000001',
lrc: `[00:00.00] 脆弱一分钟\n[00:00.00] 作曲 : 林家谦\n[00:00.00] 作词 : 徐世珍/吴辉福\n[00:00.000]编曲:林家谦\n[00:00.000]时钟不要走\n[00:04.220]让我脆弱一分钟\n[00:07.440]要多久才能习惯被放手\n[00:15.800]马克杯空了 暖暖的温热\n[00:22.660]却还在我手中停留\n[00:27.960]\n[00:29.790]勇气不要走\n[00:32.200]给我理由再冲动\n[00:35.690]去相信爱情 就算还在痛\n[00:43.960]如果我不说不会有人懂\n[00:50.720]失去你我有多寂寞\n[00:55.610]还是愿意\n[00:57.580]付出一切仅仅为了一个好梦\n[01:03.980]梦里有人真心爱我 陪我快乐也陪我沉默\n[01:11.260]没有无缘无故的痛承受越多越成熟\n[01:18.630]能让你拥抱更好的我\n[01:25.030] 谁也不要走\n[01:28.270]应该是一种奢求\n[01:31.900]可是我只想 握紧你的手\n[01:39.780]我宁愿等候 也不愿错过\n[01:46.630]你对我微笑的时候\n[01:56.780]\n[02:18.910]还是愿意\n[02:21.320]用尽全力仅仅为了一个以后\n[02:27.870]哪怕生命并不温柔哪怕被幸福一再反驳\n[02:34.870]也要相信伤痕累累 其实只是在琢磨\n[02:42.070]能让你为之一亮 的我\n[02:53.910]\n[02:56.350]制作人:林宥嘉\n[02:57.750]制作助理:张婕汝\n[02:59.010]录音师:陈文骏、叶育轩\n[03:00.410]录音室:白金录音室\n[03:01.740]混音师:SimonLi @ nOiz\n[03:03.000]OP: Terence Lam Production & Co. (Warner/Chappell Music, HK Ltd.)\n[03:04.050]SP: Warner/Chappell Music Taiwan Ltd.\n[03:04.910]OP:Universal Ms Publ Ltd Taiwan\n`
},
{
vid: '000002',
lrc: `[00:00.000]Westlife-My Love\n[00:08.800]An empty street\n[00:10.510]An empty house\n[00:12.200]A hole inside my heart\n[00:15.470]I am all alone\n[00:17.270]The rooms are getting smaller\n[00:22.440]I wonder how\n[00:23.850]I wonder why\n[00:25.460]I wonder where they are\n[00:28.870]The days we had\n[00:30.500]The songs we sang together\n[00:33.320]Oh yeah\n[00:35.480]And oh my love\n[00:38.710]I am holding on forever\n[00:42.200]Reaching for a love that seems so far\n[00:48.070]So i say a little prayer\n[00:51.100]And hope my dreams will take me there\n[00:54.520]Where the skies are blue to see you once again, my love\n[01:01.230]Over seas and coast to coast\n[01:04.430]To find a place i love the most\n[01:07.830]Where the fields are green to see you once again, my love\n[01:18.730]I try to read\n[01:20.210]I go to work\n[01:21.900]I am laughing with my friends\n[01:25.180]But i cannot stop to keep myself from thinking\n[01:29.710]Oh no I wonder how\n[01:33.420]I wonder why\n[01:34.960]I wonder where they are\n[01:38.470]The days we had\n[01:40.150]The songs we sang together\n[01:42.900]Oh yeah And oh my love\n[01:48.300]I am holding on forever\n[01:51.760]Reaching for a love that seems so far Mark:\n[01:58.070]So i say a little prayer\n[02:01.400]And hope my dreams will take me there\n[02:04.800]Where the skies are blue to see you once again, my love\n[02:11.400]Over seas and coast to coast\n[02:14.720]To find a place i love the most\n[02:18.080]Where the fields are green to see you once again, my love\n[02:24.040]To hold you in my arms\n[02:27.290]To promise you my love\n[02:30.610]To tell you from the heart\n[02:33.870]You are all i am thinking of\n[02:45.460]I am reaching for a love that seems so far\n[02:51.940]So i say a little prayer\n[02:54.820]And hope my dreams will take me there\n[02:58.080]Where the skies are blue to see you once again, my love\n[03:04.700]Over seas and coast to coast\n[03:07.980]To find a place i love the most\n[03:11.520]Where the fields are green to see you once again,my love\n[03:19.000]Where the fields are green to see you once again,my love\n[03:31.580]Over seas and coast to coast\n[03:34.670]To find a place i love the most\n[03:38.110]Where the fields are green to see you once again,my love\n[03:19.020]say a little prayer\n[03:22.300]dreams will take me there\n[03:24.770]Where the skies are blue to see you once again\n`
}
];
/** 歌曲 */
const songs = [
{
vid: '000001',
src: '//sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/music/audio.mp3',
poster:
'https://imgcache.qq.com/open_proj/proj_qcloud_v2/gateway/solution/general-video/css/img/scene/1.png'
},
{
vid: '000002',
src: '//sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/music/audio-en.mp3',
poster:
'https://imgcache.qq.com/open_proj/proj_qcloud_v2/gateway/solution/general-video/css/img/scene/6.png'
}
];
/** 播放器配置 */
const config = ref({
url: songs[0].src,
volume: 1,
height: 54,
width: '100%',
autoplay: false,
mediaType: 'audio',
marginControls: true,
controls: { initShow: true, mode: 'flex' },
ignores: [
'play',
'mobile',
'playbackrate',
'musicbackward',
'musicforward',
'musiccover',
'musicmeta',
'musicnext',
'musicprev'
],
presets: ['default', MusicPreset],
videoConfig: { crossOrigin: 'anonymous' }
});
/** 频谱容器 */
const analyzeRef = ref<HTMLCanvasElement | null>(null);
/** 歌词容器 */
const lrcRef = ref<HTMLDivElement | null>(null);
/** 当前歌曲 */
const current = ref(songs[0]);
/** 是否播放状态 */
const playing = ref(false);
interface Sate {
player: Player | null;
analyze: Analyze | null;
}
const state: Sate = {
/** 视频播放器实例 */
player: null,
/** 频谱实例 */
analyze: null
};
/** 播放器渲染完成 */
const onPlayer = (ins: Player) => {
state.player = ins;
state.player.crossOrigin = 'anonymous';
state.player.on('pause', () => {
playing.value = false;
});
state.player.on('ended', () => {
playing.value = false;
playNext();
});
state.player.on('play', () => {
playing.value = true;
// 初始化频谱
if (!state.analyze && analyzeRef.value) {
state.analyze = new Analyze(state.player, analyzeRef.value, {
stroke: 1,
mode: 'vertLines',
bgColor: 'rgba(0, 0, 0, 0)'
});
}
});
// 初始化歌词
const lyric = new Lyric(
[lyrics.find((d) => d.vid == current.value.vid)?.lrc],
lrcRef.value
);
lyric.bind(state.player);
lyric.show();
};
/** 播放/暂停 */
const playOrPause = () => {
if (state.player) {
if (state.player.paused) {
state.player.play();
} else {
state.player.pause();
}
}
};
/** 播放下一曲 */
const playNext = () => {
const index = songs.findIndex((d) => d.vid === current.value.vid);
if (index === songs.length - 1) {
current.value = songs[0];
} else {
current.value = songs[index + 1];
}
if (state.analyze) {
state.analyze.stop();
state.analyze = null;
}
config.value = { ...config.value, url: current.value.src, autoplay: true };
};
/** 播放上一曲 */
const playPrev = () => {
const index = songs.findIndex((d) => d.vid === current.value.vid);
if (index === 0) {
current.value = songs[songs.length - 1];
} else {
current.value = songs[index - 1];
}
if (state.analyze) {
state.analyze.stop();
state.analyze = null;
}
config.value = { ...config.value, url: current.value.src, autoplay: true };
};
</script>
<style lang="scss" scoped>
.music-body {
height: 325px;
position: relative;
background-color: #000;
background-repeat: no-repeat;
background-size: cover;
&::before,
&::after {
content: '';
height: 80px;
position: absolute;
top: 0;
left: 0;
width: 100%;
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0.6),
rgba(0, 0, 0, 0)
);
z-index: 2;
}
&::after {
top: auto;
bottom: 0;
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.6)
);
}
}
.lrc-wrap :deep(.xgplayer-lrcWrap) {
height: 100%;
padding: 80px 0;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
color: rgba(255, 255, 255, 0.8);
font-size: 16px;
line-height: 2;
overflow: auto;
scrollbar-width: none;
.xgplayer-lyric-item-active {
color: #e31106;
font-weight: bold;
}
&::-webkit-scrollbar {
display: none;
}
}
.analyze-wrap {
width: 100%;
height: 60px;
display: block;
position: absolute;
bottom: 0;
left: 0;
z-index: 3;
}
.music-footer {
flex-shrink: 0;
display: flex;
align-items: center;
background: #000;
color: #fff;
:deep(.xg-center-grid) {
padding-left: 0;
}
}
.music-controls {
font-size: 20px;
display: flex;
align-items: center;
.el-icon {
cursor: pointer;
margin-left: 16px;
}
}
</style>