工作之余查了很多资料一步步摸索出来的,先感谢各位大佬。
仿QQ音乐做的,不是100%还原,不过基本原理都在这了,结合之前的歌词滚动组件一起使用
页面布局拆分
总体分为
1顶部歌名+歌手的top-bar模块+模糊背景
2专辑+歌词滚动模块
3进度条+时间模块
4播放控件模块,播放,暂停,上一曲,下一曲。
第一部分
需要定一个固定在页面的div做模糊背景,然后平铺一个APP-bar
<template>
<div class="main-page" ref="MainRef">
<div
class="background-flitter"
:style="`background-image: url(${songInfo.cover})`"
>div>
<div class="top-bar">
<p>{{ songInfo.name }}p>
<p style="font-size: 0.24rem;font-weight: 500">{{ songInfo.artistsName }}p>
div>
div>
template>
具体的歌曲信息如下
data: (){
return {
{
albumId: 93162249,
albumTitle: "STRAY SHEEP",
artistsName: "米津玄師",
cover:"https://p1.music.126.net/6mhlWCOOQkT0xDjjuCLW7g==/109951165181187586.jpg",
id: 1466598056,
index: 7,
name: "Lemon",
url:"https://music.163.com/song/media/outer/url?id=1466598056.mp3",
},
}
}
至此完成整体背景和top-bar部分
##第二部分,专辑+歌词滚动
左右滑动切换用到了swiper组件,专辑+歌词和纯歌词分别放在两个slide就可以了。
先固定一个歌词容器,与top-bar同级,具体代码可以参考歌词组件封装来看,都是复用的代码。
移动端歌词滚动组件
<div class="lyric-container">
<div class="swiper-contain">
<div class="swiper-wrapper">
<div class="swiper-slide">
<div class="disc-cover">
<div class="disc" ref="rotate">//ref="rotate"
<img :src="songInfo.cover" alt="" />
div>
div>
<div class="text-container">
<div class="text-list" :style="lyricMiniTop">
<p
v-for="(item, index) in lyricInfo"
:key="index"
:style="{
color:
lyricIndex === index
? colorLight
: color,
}"
>
{{ item.lyric }}
p>
div>
div>
div>
<div class="swiper-slide">
<l-scroll
ref="lyric"
:color="color"
:colorLight="colorLight"
:lineHeight="lineHeight"
:paddingTop="paddingTop"
:fontSize="fontSize"
:lyricIndex="lyricIndex"
:lyricsList="lyricInfo"
>l-scroll>
div>
div>
div>
div>
唱片旋转效果animation和animation-play-state: paused;
.disc {
width: 5rem;
height: 5rem;
border-radius: 50%;
box-shadow: 0 0 0 0.2rem rgba(255, 255, 255, 0.4);
animation: animations1 12s linear infinite forwards;
animation-play-state: paused;
overflow: hidden;
img {
width: 100%;
height: 100%;
}
}
@keyframes animations1 {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
在播放事件中添加
//播放与暂停
play() {
if (this.playing) {
// 播放中,点击则为暂停
this.playing = false;
this.$refs.rotate.style.animationPlayState = "paused";
audio.pause();
} else {
// 暂停中,点击则为播放
this.playing = true;
this.$refs.rotate.style.animationPlayState = "running";
audio.play();
}
},
到这完成了歌词滚动和切换
第三部分,进度条点击和拖拽控制播放进度
样式,时长比这些都讲烂了,讲讲点击和拖拽控制播放进度吧
拖拽功能:给拖拽按钮,也就是示例图的白色进度按钮添加三个事件
用拖动后的X坐标-起始坐标变得到拖动的位移距离,再比上总进度距离就得到当前播放百分比了
<div
class="play-point"
@touchstart.stop.prevent="touchstart"
@touchmove.stop.prevent="touchmove"
@touchend.stop.prevent="touchend"
:style="{
transform: 'translateX(' + thumbTranslateX + 'rem)',
}"
>div>
//控制播放进度
SetProgress(t) {
audio.currentTime = audio.duration * t;
},
touchstart(event) {
let progressL = this.$refs.track.offsetWidth ; // 进度条总宽度
let allL = this.$refs.MainRef.offsetWidth ; // 页面总宽度
//因为我的结构如上图,总宽度-进度条除2得到进度条距离左边的X值
let half = (allL-progressL)/2
console.log("开始", progressL, allL, half)
//记录开始的X轴坐标
if (this.startXFirst) {
this.startX = half;
this.startXFirst = false;
}
},
touchmove(event) {
let moveX = parseInt(
(event.changedTouches[0].clientX - this.startX)
);
let progressL = this.$refs.track.offsetWidth; // 进度条总长
let percent = (moveX / progressL).toFixed(2); //拖动%比
if(percent>1){
percent = 1
}
this.audioPercent = percent; //音频播放%
this.thumbTranslateX = this.audioPercent * 4; //计算滑块位移
},
touchend(event) {
console.log("结束",event)
this.finalX = parseInt(
event.changedTouches[0].clientX - this.startX
);
let progressL = this.$refs.track.offsetWidth; // 进度条总长
let time = (this.finalX / progressL).toFixed(2);
if(time>1){
time = 1
}
this.SetProgress(time);
},
点击实现进度则简单多了,
<div
class="progress"
@click="HandleProgressClick($event)"
ref="track"
>
<div
class="progress_box"
:style="{ width: audioProgressPercent }"
>div>
<div
class="play-point"
@touchstart.stop.prevent="touchstart"
@touchmove.stop.prevent="touchmove"
@touchend.stop.prevent="touchend"
:style="{
transform: 'translateX(' + thumbTranslateX + 'rem)',
}"
>div>
div>
//点击进度条
HandleProgressClick(event) {
let progressL = this.$refs.track.offsetWidth; // 进度条总长
let clickX = event.offsetX;
let time = (clickX / progressL).toFixed(2);
this.SetProgress(time);
},
OK ,第三部分完成
第四部分就是上一曲下一曲播放暂停了,这些都是别人讲了好多遍的就不赘述了。
有疑问或者更多想法的都可以提出来一起探讨~