a. QQ音乐播放器静态页面布局
* 页面整体布局规划和实现
* 页面顶部布局和静态效果
* 工具条布局和静态效果
* 音乐列表布局和静态效果
* 自定义滚动条效果
* 歌曲信息的展示效果
* 底部播放布局和静态效果
* 页面整体的高斯模糊效果
b. QQ音乐播放器加载并播放歌曲
* 实现音乐动态加载逻辑
* 实现底部音乐控制图标的动态切换
* 实现底部音乐播放状态的动态切换
* 实现音乐序号的动画效果
c. QQ音乐播放器操作歌曲(切换、删除等)
* 实现音乐的播放、暂停功能
* 实现音乐切换(切歌)功能
* 实现音乐删除功能
d. QQ音乐播放器歌词加载、显示和同步
* 实现解析歌词并动态加载功能
* 实现歌词与歌曲播放进度同步功能
e. 拖动音乐进度条调整音乐播放进度功能
首先要先布局
头部header、中间区域content、底部footer和背景mask_bg
<div class="header">
<h1 class="logo"><a href="#">a>h1>
<ul class="register">
<li>注册li>
<li>登陆li>
ul>
div>
<div class="content">
<div class="content_in">div>
div>
<div class="footer">
<div class="footer_in">div>
div>
<div class="mask_bg">div>
工具条(收藏、添加到、下载、删除、清空列表),利用雪碧图完成图片
<div class="content_in">
<div class="content_left">
<div class="content_toolbar">
<span><i>i>收藏span>
<span><i>i>添加到span>
<span><i>i>下载span>
<span><i>i>删除span>
<span><i>i>清空列表span>
div>
div>
div>
<ul>
<li class="list_title">
<div class="list_check"><i>i>div>
<div class="list_number">div>
<div class="list_name">歌曲div>
<div class="list_singer">歌手div>
<div class="list_time">时长div>
li>
ul>
div>
- 可以点击选项框
- 再点击每一行的时候会出现暂停,添加,下载,转发,删除等,换到下一行的时候其他行会淡入淡出的消失
function initEvents() {
// 1.监听歌曲的移入移出事件
// 要用事件委托因为歌曲都是新增的
$(".content_list").delegate(".list_music", "mouseenter", function () {
//find 搜索所有与指定表达式相匹配的元素,这个函数是找出正在处理的元素的后代元素的好方法
//如果直接用$('.list_menu')所有菜单会一起显示出来
// 显示子菜单
$(this).find(".list_menu").stop().fadeIn(100);
$(this).find(".list_time a").stop().fadeIn(100);
// 隐藏时长
$(this).find(".list_time span").stop().fadeOut(100);
});
$(".content_list").delegate(".list_music", "mouseleave", function () {
// 隐藏子菜单
$(this).find(".list_menu").stop().fadeOut(100);
$(this).find(".list_time a").stop().fadeOut(100);
// 显示时长
$(this).find(".list_time span").stop().fadeIn(100);
});
/*
addClass()是在原有的类基础上增加类属性,仍然保留原有的类的样式
toggleClass() 是切换元素class类别,删除原有的class样式,替换为新的class样式. (切换,没有加,有减)
*/
// 2.监听复选框的点击事件
$(".content_list").delegate(".list_check", "click", function () {
$(this).toggleClass("list_checked");//有就删除,没有就添加
});
}
自定义滚动条运用到了jQuery的插件,可以利用这个插件来设置不同样式的滚动条 — jQuery custom content scroller
如果不喜欢可以修改默认样式
._mCS_1 .mCSB_dragger .mCSB_dragger_bar{ background-color: red; }
._mCS_2 .mCSB_dragger .mCSB_dragger_bar{ background-color: green; }
#mCSB_3_dragger_vertical .mCSB_dragger_bar{ background-color: blue; }
#mCSB_1_scrollbar_vertical .mCSB_dragger{ height: 100px; }
#mCSB_1_scrollbar_horizontal .mCSB_dragger{ width: 100px; }
.mCSB_1_scrollbar .mCSB_dragger .mCSB_draggerRail{ width: 4px; }
<div class="content_right">
<div class="song_info">
<a href="javascript:;" class="song_info_pic">
<img src="https://s1.ax1x.com/2020/06/20/NQ3rSx.jpg" alt="">
a>
<div class="song_info_name">歌曲名称:
<a href="javascript:;">111a>
div>
<div class="song_info_singer">歌手名:
<a href="javascript:;">222a>
div>
<div class="song_info_ablum">专辑名:
<a href="javascript:;">333a>
div>
div>
<div class="song_lyric_container">
<ul class="song_lyric">
<li class="cur">第一条歌词li>
<li>第二条歌词li>
ul>
div>
div>
/* 右上内容 */
.content_right .song_info{
text-align: center;
color: rgba(255,255,255,0.5);
line-height: 30px;
}
.song_info .song_info_pic{
display: inline-block;
background: url("https://s1.ax1x.com/2020/06/20/NQ3aTJ.png") no-repeat 0 0;
width: 201px;
height: 180px;
text-align: left;
border-radius: 50%;
}
.song_info_pic img{
width: 180px;
height: 180px;
border-radius: 50%;
}
.song_info div a{
text-decoration: none;
color: #fff;
opacity: 0.5;
}
.song_info div a:hover{
opacity: 1;
}
/* 右下歌词 */
.content_right .song_lyric_container{
margin-top: 30px;
height: 150px;
overflow: hidden;
}
.content_right .song_lyric{
/* background: greenyellow; */
text-align: center;
margin-top: 30px;
/* overflow: hidden; */
}
.content_right .song_lyric li{
list-style: none;
line-height: 30px;
font-weight: bold;
color: rgba(255,255,255,0.5);
}
.content_right .song_lyric .cur{
color: #31c27c;
}
底部footer
<div class="footer">
<div class="footer_in">
<a href="javascript:;" class="music_pre">a>
<a href="javascript:;" class="music_play">a>
<a href="javascript:;" class="music_next">a>
<div class="music_progress_info">
<div class="music_progress_top">
<span class="music_progress_name">111span>
<span class="music_progress_time">00:00 / 05:23span>
div>
<div class="music_progress_bar">
<div class="music_progress_line">
<div class="music_progress_dot">div>
div>
div>
div>
<a href="javascript:;" class="music_mode">a>
<a href="javascript:;" class="music_fav">a>
<a href="javascript:;" class="music_down">a>
<a href="javascript:;" class="music_comment">a>
<a href="javascript:;" class="music_only">a>
<div class="music_voice_info">
<a href="javascript:;" class="music_voice_icon">a>
<div class="music_voice_bar">
<div class="music_voice_line">
<div class="music_voice_dot">div>
div>
div>
div>
div>
div>
/* 底部 */
.footer{
width: 100%;
height: 80px;
/* background: green; */
position: absolute;
left: 0;
bottom: 0;
}
/* 版型 */
.footer .footer_in{
width: 1200px;
height: 100%;
/* background: purple; */
margin: 0 auto;
user-select: none;
}
.footer_in a{
display: inline-block;
text-decoration: none;
color: #fff;
background: url("https://s1.ax1x.com/2020/06/20/NQYwDK.png") no-repeat 0 0;
margin-right: 20px;
}
.footer_in .music_pre{
width: 19px;
height: 20px;
background-position: 0 -30px;
}
.footer_in .music_play{
width: 21px;
height: 29px;
background-position: 0 0;
vertical-align: -5px;
}
.footer_in .music_play2{
background-position: -30px 0;
}
.footer_in .music_next{
width: 19px;
height: 20px;
background-position: 0 -52px;
}
.footer_in .music_progress_info{
display: inline-block;
width: 670px;
height: 40px;
position: relative;
top: 10px;
}
.music_progress_info .music_progress_top{
width: 100%;
height: 30px;
line-height: 30px;
color: #fff;
}
.music_progress_top .music_progress_name{
float: left;
opacity: 0.5;
}
.music_progress_top .music_progress_name:hover{
opacity: 1;
}
.music_progress_top .music_progress_time{
float: right;
opacity: 0.5;
}
.music_progress_info .music_progress_bar{
width: 100%;
height: 4px;
background: rgba(255,255,255,0.5);
margin-top: 5px;
position: relative;
}
.music_progress_bar .music_progress_line{
width: 0px;
height: 100%;
background: #fff;
}
.music_progress_line .music_progress_dot{
width: 14px;
height: 14px;
border-radius: 50%;
background: #fff;
position: absolute;
top: -5px;
left: 0px;
}
.footer_in .music_mode{
width: 26px;
height: 25px;
background-position: 0 -205px;
}
.footer_in .music_mode2{
width: 23px;
height: 20px;
background-position: 0 -260px;
}
.footer_in .music_mode3{
width: 25px;
height: 19px;
background-position: 0 -74px;
}
.footer_in .music_mode4{
width: 26px;
height: 25px;
background-position: 0 -232px
}
.footer_in .music_fav{
width: 24px;
height: 21px;
background-position: 0 -96px;
}
.footer_in .music_fav2{
background-position: -30px -96px;
}
.footer_in .music_down{
width: 22px;
height: 21px;
background-position: 0 -120px;
}
.footer_in .music_comment{
width: 24px;
height: 24px;
background-position: 0 -400px;
}
.footer_in .music_only{
width: 74px;
height: 27px;
background-position: 0 -281px;
}
.footer_in .music_only2{
background-position: 0 -310px;
}
.footer_in .music_voice_info{
display: inline-block;
width: 100px;
height: 40px;
line-height: 40px;
position: relative;
top: 10px;
}
.music_voice_info .music_voice_icon{
width: 26px;
height: 21px;
background-position: 0 -144px;
position: absolute;
left: 0;
top: 10px;
}
.music_voice_info .music_voice_icon2{
background-position: 0 -182px;
}
.music_voice_info .music_voice_bar{
width: 70px;
height: 4px;
background: rgba(255,255,255,0.5);
position: absolute;
right: 0;
top: 18px;
}
.music_voice_bar .music_voice_line{
width: 70px;
height: 100%;
background: #fff;
}
.music_voice_line .music_voice_dot{
width: 14px;
height: 14px;
border-radius: 50%;
background: #fff;
position: relative;
top: -5px;
left: 70px;
}
这里就要利用ajax方法
// 1.加载歌曲列表
getPlayerList();
function getPlayerList() {
$.ajax({
//从哪加载
url: "./source/musiclist.json",
//加载的是什么类型
dataType: "json",
// 成功之后做什么
success: function (data) {
player.musicList = data;
// 3.1遍历获取到的数据, 创建每一条音乐
var $musicList = $(".content_list ul");
$.each(data, function (index, ele) {
var $item = crateMusicItem(index, ele);
$musicList.append($item);
});
initMusicInfo(data[0]);
initMusicLyric(data[0]);
},
// 失败之后做什么
error: function (e) {
console.log(e);
}
});
}
getPlayerList();
// 定义一个方法创建一条音乐
function crateMusicItem(index, music) {
var $item = $("" +
"- \n"
+
"\n" +
""+(index + 1)+"\n" +
""+music.name+"" +
" \n"+
"\n" +
""+music.singer+"\n" +
"\n" +
"
完成音乐播放时图标切换
保证歌曲条目开始或暂停时让底部的保持同步
// 3.添加子菜单播放按钮的监听
var $musicPlay = $(".music_play");
$(".content_list").delegate(".list_menu_play", "click", function () {
var $item = $(this).parents(".list_music");
// console.log($item.get(0).index);
// console.log($item.get(0).music);
// 3.1切换播放图标
$(this).toggleClass("list_menu_play2");
// 3.2复原其它的播放图标
//先找点击的祖先list_music,再用siblings()方法找list_music的兄弟 $item.siblings().find(".list_menu_play").removeClass("list_menu_play2");
// 3.3同步底部播放按钮
if($(this).hasClass("list_menu_play2") !=-1){
// 能找到list_menu_play2
// 当前子菜单的播放按钮是播放状态
$musicPlay.addClass("music_play2");
// 让文字高亮
$item.find("div").css("color", "#fff");
$item.siblings().find("div").css("color", "rgba(255,255,255,0.5)");
}else{
// 当前子菜单的播放按钮不是播放状态
$musicPlay.removeClass("music_play2");
// 让文字不高亮
$item.find("div").css("color", "rgba(255,255,255,0.5)");
}
});
// 3.4切换序号的状态
$item.find(".list_number").toggleClass("list_number2");
$item.siblings().find(".list_number").removeClass("list_number2");
播放暂停音乐
function Player($audio) {
return new Player.prototype.init($audio);
}
Player.prototype = {
constructor: Player,
musicList: [],
init: function ($audio) {
this.$audio = $audio;
this.audio = $audio.get(0);
},
currentIndex: -1, // 4 3
playMusic: function (index, music) {
// 判断是否是同一首音乐
if(this.currentIndex == index){
// 同一首音乐
if(this.audio.paused){
this.audio.play();
}else{
this.audio.pause();
}
}else {
// 不是同一首
this.$audio.attr("src", music.link_url);
this.audio.play();
this.currentIndex = index;
}
}
}
实现底部栏的上一曲/下一曲/暂停
// 5.监听底部控制区域上一首按钮的点击
$(".music_pre").click(function () {
$(".list_music").eq(player.preIndex()).find(".list_menu_play").trigger("click");
});
// 6.监听底部控制区域下一首按钮的点击
$(".music_next").click(function () {
$(".list_music").eq(player.nextIndex()).find(".list_menu_play").trigger("click");
});
// 4.监听底部控制区域播放按钮的点击
$musicPlay.click(function () {
// 判断有没有播放过音乐
if(player.currentIndex == -1){
// 没有播放过音乐
$(".list_music").eq(0).find(".list_menu_play").trigger("click");
}else{
// 已经播放过音乐
$(".list_music").eq(player.currentIndex).find(".list_menu_play").trigger("click");
}
});
删除音乐操作
// 7.监听删除按钮的点击
$(".content_list").delegate(".list_menu_del", "click", function () {
// 找到被点击的音乐
var $item = $(this).parents(".list_music");
// 判断当前删除的是否是正在播放的
if($item.get(0).index == player.currentIndex){
$(".music_next").trigger("click");
}
item.remove();
player.changeMusic($item.get(0).index);
// 重新排序
$(".list_music").each(function (index, ele) {
ele.index = index;
$(ele).find(".list_number").text(index + 1);
});
});
在点击切换上一曲/下一曲/删除后,要随时切换歌曲名称、歌手名、专辑名、歌词和时间等
// 2. 初始化歌曲信息
function initMusicInfo(music) {
// 获取对应的元素
var $musicImage = $(".song_info_pic img");
var $musicName = $(".song_info_name a");
var $musicSinger = $(".song_info_singer a");
var $musicAblum = $(".song_info_ablum a");
var $musicProgressName = $(".music_progress_name");
var $musicProgressTime = $(".music_progress_time");
var $musicBg = $(".mask_bg");
// 给获取的到的元素赋值
$musicImage.attr("src", music.cover);
$musicName.text(music.name);
$musicSinger.text(music.singer);
$musicAblum.text(music.album);
$musicProgressName.text(music.name + "/" + music.singer);
$musicProgressTime.text("00:00 / " + music.time);
$musicBg.css("background", 'url("' + music.cover + '")');
}
// 3.初始化歌词信息
function initMusicLyric(music){
lyric = new Lyric(music.link_lrc);
var $lryicContainer = $(".song_lyric");
// 清空上一首音乐的歌词
$lryicContainer.html("");
lyric.loadLyric(function () {
// 创建歌词列表
$.each(lyric.lyrics, function (index, ele) {
var $item = $("" +ele+"");
$lryicContainer.append($item);
});
});
}
$.ajax({
success: function (data) {
initMusicInfo(data[0]);
},
});
$(".content_list").delegate(".list_menu_play", "click", function () {
// 3.6 切换歌曲信息
initMusicInfo($item.get(0).music);
});
进度条
musicTimeUpdate: function (callBack) {
var $this = this;
this.$audio.on("timeupdate", function () {
var duration = $this.audio.duration;
var currentTime = $this.audio.currentTime;
var timeStr = $this.formatDate(currentTime, duration);
callBack(currentTime, duration, timeStr);
});
},
formatDate: function (currentTime, duration) {
var endMin = parseInt(duration / 60); // 2
var endSec = parseInt(duration % 60);
if(endMin < 10){
endMin = "0" + endMin;
}
if(endSec < 10){
endSec = "0" + endSec;
}
var startMin = parseInt(currentTime / 60); // 2
var startSec = parseInt(currentTime % 60);
if(startMin < 10){
startMin = "0" + startMin;
}
if(startSec < 10){
startSec = "0" + startSec;
}
return startMin+":"+startSec+" / "+endMin+":"+endSec;
}
player.musicTimeUpdate(function (currentTime, duration, timeStr) {
// 同步时间
$(".music_progress_time").text(timeStr);
}
// 8.监听播放的进度
player.musicTimeUpdate(function (currentTime, duration, timeStr) {
// 同步进度条
// 计算播放比例
var value = currentTime / duration * 100;
progress.setProgress(value);
// 实现歌词同步
var index = lyric.currentIndex(currentTime);
var $item = $(".song_lyric li").eq(index);
$item.addClass("cur");
$item.siblings().removeClass("cur");
// 实现歌词滚动
if(index <= 2) return;
$(".song_lyric").css({
marginTop: (-index + 2) * 30
});
});
下载地址
前端调用后端服务接口时
第一种
打开cmd
,然后找到所在项目目录下,先安装npm install -g live-server
接下来输入live-server
,回车
注意这里默认打开的是index.html
live-server实时简易服务器
第二种