jQuery——QQ音乐案例

时间:2024-10-14 07:45:05

代码见 /minmin233/QQmusic–jQuery

结构

头部

在这里插入图片描述

<div class="header">
	<h1 class="logo"><a href="#"></a></h1>
	<ul class="login">
		<li>登录</li>
		<li>设置</li>
	</ul>
</div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
.header{
	width: 100%;
	height: 45px;
	background: #31c27c;
}
.header .logo{
	float: left;
	margin-left: 20px;
}
.header .logo a{
	display: inline-block;
	width: 78px;
	height: 21px;
	background: url("../images/") no-repeat;
}
.header .login{
	float: right;
	line-height: 45px;
}
.header .login li{
	list-style: none;
	float: left;
	margin-right:20px;
	color:#fff;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

中间内容区

在这里插入图片描述
在这里插入图片描述

中间内容区可以划分为一左一右
左边可以分为一上一下
1.上面是五个按钮,按钮中有边框,有图片,有文字
2.下面是歌曲列表,歌曲列表的歌曲可以选中,鼠标悬停的时候会显示子菜单
2.1复选框选中的√是个图片,设置这个图片的位置,弄一个类添加移除
2.2禁用li的选中事件
2.3超出出现滚动条,优化滚动条,用插件,有引入顺序问题
右边可以分为一上一下
1.上面是歌曲基本信息
2.下面是歌词展示
在这里插入图片描述

<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 class="content_list" data-mcs-theme="minimal-dark">
	<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>

<li class="list_music">
	<div class="list_check"><i></i></div>
	<div class="list_number">1</div>
	<div class="list_name">从零玩转编程开发
		<div class="list_menu">
			<a href="javascript:;" title="播放"></a>
			<a href="javascript:;" title="添加"></a>
			<a href="javascript:;" title="下载"></a>
			<a href="javascript:;" title="分享"></a>
		</div>
	</div>
	<div class="list_singer">李南江</div>
	<div class="list_time">
		<span>04:18</span>
		<a href="javascript:;" title="删除"></a>
	</div>
</li>

<div class="song_info">
	<a href="javascript:;" class="song_info_pic">
		<img src="../images/" alt="">
	</a>
	<div class="song_info_name">歌曲名称:
		<a href="javascript:;">从零玩转编程开发</a>
	</div>
	<div class="song_info_singer">歌手名:
		<a href="javascript:;">李南江</a>
	</div>
	<div class="song_info_ablum">专辑名:
		<a href="javascript:;">从零玩转系列</a>
	</div>
</div>

<div class="song_lyric_container">
	<ul class="song_lyric">
		<li>1</li>
		<li>2</li>
	</ul>
</div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
/*精灵图*/
.content_toolbar span i{
	display: inline-block;
	width: 18px;
	height: 18px;
	background: url("../images/icon_sprite.png") no-repeat 0 0;
	margin-right: 10px;
	vertical-align: -5px;
}
.content_toolbar span:nth-child(1) i{
	background-position: -60px -20px;
}
.content_toolbar span:nth-child(2) i{
	background-position: -20px -20px;
}
.content_toolbar span:nth-child(3) i{
	background-position: -40px -240px;
}
.content_toolbar span:nth-child(4) i{
	background-position: -100px -20px;
}
.content_toolbar span:nth-child(5) i{
	background-position: -40px -300px;
}
/*滚动条*/
.content_left .content_list{
	width: 100%;
	height: 420px;
	overflow: auto;/*超出出现滚动条*/
}
/*每条歌曲*/
.content_list li{
	list-style: none;
	width: 100%;
	height: 50px;
	background: orange;
	opacity: 0.5;
	border-bottom: 1px solid rgba(255, 255, 255, 0.5);
	box-sizing: border-box;
	user-select: none; /*禁用选中*/
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

底部控制区

在这里插入图片描述

进度条由三个部分组成,乳白色的背景,纯白色的前景,小圆点;
声音控制区由一个图标和一个进度条组成;
图标对齐方式;
控制图标的切换,播放按钮,循环模式按钮,喜欢按钮,纯净模式按钮
在这里插入图片描述

<!-- 进度条 -->
<div class="music_progress_info">
	<div class="music_progress_top">
		<span class="music_progress_name">从零玩转编程开发 / 李江南</span>
		<span class="music_progress_time">00:00 / 05:23</span>
	</div>
	<div class="music_progress_bar">
		<div class="music_progress_line">
			<div class="music_progress_dot"></div>
		</div>
	</div>
</div>
<!-- 声音控制区 -->
<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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
/*贴着底部*/
.footer{
	width: 100%;
	height: 80px;
	position: absolute;
	left: 0;
	bottom: 0;
}
/*进度条*/
.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;
	color: #fff;
	line-height: 30px;
}
.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;
}
.music_progress_bar .music_progress_line{
	height: 100%;
	background: #fff;
}
.music_progress_line .music_progress_dot{
	width: 14px;
	height: 14px;
	border-radius: 50%;
	background: #fff;
	position: relative;
	top:-5px;
}
/*声音控制区*/
.footer_in .music_voice_info{
	display: inline-block;
	width: 100px;
	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_bar{
	width: 70px;
	height: 4px;
	background: rgba(255, 255,255,0.5);
	position: absolute;
	right: 0;
	top: 18px;
}
.music_voice_bar .music_voice_line{
	height: 100%;
	background: #fff;
}
.music_voice_line .music_voice_dot{
	width: 14px;
	height: 14px;
	border-radius: 50%;
	background: #fff;
	position: relative;
	top:-5px;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87

中间内容区和底部控制区有版型

让版型居中

.content .content_in{
	width: 1200px;
	height: 100%;
	margin:0 auto;
}
.footer .footer_in{
	width: 1200px;
	height: 100%;
	margin:0 auto;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

样式

复选框点击高亮

.content_list .list_check i{
	display: inline-block;
	width: 14px;
	height: 14px;
	border: 1px solid #fff;
	opacity: 0.5;
}
.content_list .list_checked i{
	background: url("../images/icon_sprite.png") no-repeat -60px -80px;
	opacity: 1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

鼠标移到子菜单时高亮

.list_menu a{
	display: inline-block;
	width: 36px;
	height: 36px;
	background: url("../images/icon_list_menu.png") no-repeat 0 0;
	opacity: 0.5;
}
.list_menu a:hover{
	opacity: 1;
}

.content_list .list_time a{
	width: 36px;
	height: 36px;
	float: left;
	background: url("../images/icon_list_menu.png") no-repeat -120px -160px;
	margin-top: 5px;
	display: none;
	opacity: 0.5;
}
.content_list .list_time a:hover{
	opacity: 1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

高斯模糊背景

<div class="mask_bg"></div>
<div class="mask"></div>
  • 1
  • 2
.mask_bg{
	position: absolute;
	left: 0;
	top: 0;
	z-index: -2;
	width: 100%;
	height: 100%;
	background: url("../images/") no-repeat 0 0;
	background-size: cover;/*填满整个屏幕*/
	filter: blur(100px);/*值越大越模糊*/
}
.mask{
	position: absolute;
	left: 0;
	top: 0;
	z-index: -1;
	width: 100%;
	height: 100%;
	background:rgba(0,0,0,0.35);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

事件

加载歌曲列表

存在跨域问题;
动态创建的元素要添加事件,只能通过事件委托;

// 1.加载歌曲列表
getPlayerList();
function getPlayerList() {
	// 可以加载本地文件,也可以加载网络文件
	$.ajax({
		url: "./source/",
		dataType: "json",
		success: function (data) {
			player.musicLists = data;
			// 遍历获取到的数据创建每一条音乐
			$.each(data, function (index, ele) {
				var $item = createMusicItem(index, ele);
				var $musicList = $(".content_list ul");
				$musicList.append($item);
			});
			initMusicInfo(data[0]);
			initLyricInfo(data[0]);
		},
		error: function (e) {
			console.log(e);
		}
	});
}

// 定义一个方法创建一条音乐
function createMusicItem(index, music){
	var $item = $(`<li class="list_music">
								<div class="list_check"><i></i></div>
								<div class="list_number">`+ (index+1) + `</div>
								<div class="list_name">`+ music.name +`
									<div class="list_menu">
										<a href="javascript:;" title="播放" class="list_menu_play"></a>
										<a href="javascript:;" title="添加"></a>
										<a href="javascript:;" title="下载"></a>
										<a href="javascript:;" title="分享"></a>
									</div>
								</div>
								<div class="list_singer">`+ music.singer +`</div>
								<div class="list_time">
									<span>` + music.time + `</span>
									<a href="javascript:;" title="删除" class="list_menu_del"></a>
								</div>
							</li>`);
	$item.get(0).index = index; // 拿到原生的li中歌曲的索引
	$item.get(0).music = music; // 拿到原生的li中的歌曲
	return $item;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

播放图标切换

找到动态添加到播放按钮,添加子菜单播放按钮的监听;
播放和暂停按钮相互切换;
当点击第一首歌曲播放后,又点击第二首歌曲播放时,第一首歌会还原;
同步底部播放按钮,点击上面音乐的播放按钮时,底部的播放按钮会同步更新

.list_menu .list_menu_play1{
	background-position: -80px -200px !important;
}
  • 1
  • 2
  • 3
// 添加子菜单播放按钮的监听
var $musicPlay = $(".music_play");
$(".content_list").delegate(".list_menu_play","click",function(){
	// 1.切换播放图标
	$(this).toggleClass("list_menu_play1");
	// 2.复原其他的播放图标
	$(this).parents(".list_music").siblings().find(".list_menu_play").removeClass("list_menu_play1");
	// 3.同步底部播放按钮
	if ($(this).attr("class").indexOf("list_menu_play1") != -1){
		// 当前子菜单是播放状态
		$musicPlay.addClass("music_play1");
	}else{
		// 当前子菜单不是播放状态
		$musicPlay.removeClass("music_play1");
	}
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

点击播放按钮,文字高亮

// 让文字高亮	
$(this).parents(".list_music").find("div").css("color","#fff");
// 还原其他文字	
$(this).parents(".list_music").siblings().find("div").css("color", "rgba(255,255,255,0.5)");
  • 1
  • 2
  • 3
  • 4

序号动画

音乐在播放时,隐藏序号,显示播放动画,
播放动画是一个背景图片,新增一个类,切换是否显示播放动画

.content_list .list_number{
	width: 20px;
	height: 100%;
}
.content_list .list_number1{
	color: transparent !important;
	background: url("../images/") no-repeat 0 center;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
// 切换序号的状态
$(this).parents(".list_music").find(".list_number").toggleClass("list_number1");
// 还原其他序号的状态
$(this).parents(".list_music").siblings().find(".list_number").removeClass("list_number1");
  • 1
  • 2
  • 3
  • 4

音乐播放暂停

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;
	}
},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

底部音乐控制

播放按钮,
如果从来没播放过音乐,点击播放按钮,默认播放第0首音乐,
播放第0首音乐,相当于点击第0首音乐的子菜单,
先找到第0首音乐的li,再找到li中的播放按钮,触发一下点击事件;
如果已经播放过音乐,点击要么暂停,要么继续播放;
上一首,
当前索引-1,当减到负数的时候,回到最后一首
下一首,
当前索引+1,当比歌曲长度还大的时候,回到第一首

// 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");
	}
})
// 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");
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

删除音乐按钮

找到删除按钮对应的这条音乐,还要有数据的同步,
删除后歌曲的序号要重新排序;
删除的是当前正在播放的音乐,那么自动播放下一首,相当于点击下一首按钮;
如果删除的是正在播放的音乐的前面的音乐,那么点击下一首,则播放下下首音乐,是因为删除歌曲后,歌曲重新排序,但是currentIndex没有变化

// 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.changeMusicLists($item.get(0).index);
	// 重新排序
	$(".list_music").each(function(index,ele){
		ele.index = index;
		$(ele).find(".list_number").text(index + 1);
	})
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

歌曲信息的切换

初始化时是第0首歌曲的信息
播放时切换歌曲信息
1.中间内容区右边歌曲信息的切换
2.底部控制区中间进度条歌曲信息的切换
3.整个背景的色调歌曲信息的切换

// 2.初始化歌曲信息
function initMusicInfo(music) {
	$(".song_info_pic img").attr("src", music.cover);
	$(".song_info_name a").text(music.name);
	$(".song_info_singer a").text(music.singer);
	$(".song_info_ablum a").text(music.ablum);

	$(".music_progress_name").text(music.name + " / " + music.singer);
	$(".music_progress_time").text("00:00 / " + music.time);

	$(".mask_bg").css("background", "url('" + music.cover + "')");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
'
运行

进度条

把进度条封装到单独的类

(function (window) {
	function Progress($progressBar, $progressLine, $progressDot) {
		return new Progress.prototype.init($progressBar, $progressLine, $progressDot);
	}
	Progress.prototype = {
		constructor: Progress,
		init: function ($progressBar, $progressLine, $progressDot) {
			this.$progressBar = $progressBar; 
			this.$progressLine = $progressLine;
			this.$progressDot = $progressDot;
		},
		isMove:false,
		progressClick:function(callBack){
			var $this = this; //谁调用这个方法,this就是谁,此时的this是progress 
			// 监听背景的点击
			this.$progressBar.click(function(event){
				// 获取背景默认距离窗口的位置
				var normalLeft = $(this).offset().left; // 此时的this是progressBar
				// 获取点击的位置距离窗口的位置
				var eventLeft = event.pageX;
				// 设置前景的宽度
				$this.$progressLine.css("width", eventLeft - normalLeft);
				// 设置小圆点的位置
				$this.$progressDot.css("left", eventLeft - normalLeft);
				
				// 计算进度条的比例
				var value = (eventLeft - normalLeft) / $(this).width();
				callBack(value);
			})
		},
		progressMove:function(callBack){
			var $this = this;
			// 获取背景距离窗口默认的位置
			var normalLeft = this.$progressBar.offset().left;
			var eventLeft; //点击的位置距离窗口的位置
			// 获取进度条的宽度
			var barWidth = this.$progressBar.width();
			// 1.监听鼠标的按下
			this.$progressBar.mousedown(function(){
				// 2.监听鼠标的移动
				$(document).mousemove(function(event){
					$this.isMove = true;
					// 获取点击的位置距离窗口的位置
					eventLeft = event.pageX;
					var offset = eventLeft - normalLeft;
					if (offset >= 0 && offset <= barWidth){
						// 设置前景的宽度
						$this.$progressLine.css("width", offset);
						$this.$progressDot.css("left", offset);
					}
					/* // 计算进度条的比例
					var value = (eventLeft - normalLeft) / $(this).width();;
					callBack(value); */
				})

			})
			// 3.监听鼠标的弹起
			$(document).mouseup(function () {
				$(document).off("mousemove");
				this.isMove=false;
				// 计算进度条的比例
				var value = (eventLeft - normalLeft) / $this.$progressBar.width();;
				callBack(value);
			})
		},
		setProgress:function(value){
			if(this.isMove) return;
			if(value < 0 || value > 100) return;
			this.$progressLine.css({
				width:value+"%"
			});
			this.$progressDot.css({
				left: value + "%"
			});
		}
	}
	Progress.prototype.init.prototype = Progress.prototype;
	window.Progress = Progress;
})(window);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79

点击

操作背景,操作前景,操作小圆点
设置前景,设置小圆点的位置

拖拽

按下鼠标不放,然后拖拽
在拖拽的过程中,不断修改前景的宽度和小圆点的位置;
鼠标弹起之后,停止修改,就是移除拖拽的事件
有三个事件,鼠标的按下,移动,弹起;
其中,鼠标的移动事件必须在鼠标的按下事件当中执行,监听移动事件不能用进度条来监听,如果这样,鼠标只能在进度条内才有效果

同步

播放时间的同步

监听当前被播放歌曲的进度,timeupdate
获取当前正在播放音乐的总时长,和已经播放的时长

进度条的同步

计算播放比例

歌曲同步

点击小圆点,拖拽小圆点
可以得到此时前景的宽度,背景的宽度
可以得到获取音乐的总时长
设置音乐跳转的位置

拖拽的时候设置了前景的宽度
同步进度条的时候设置了前景的宽度
冲突了

拖拽的时候不会设置音乐从什么时候开始播放,
松手时候才设置

优化

把播放控制相关的代码都要放到中

// 9.监听播放的进度
player.$audio.on("timeupdate",function(){
	var duration = player.getMusicDuration();
	var currentTime = player.getMusicCurrentTime();
	var timeStr = formatDate(currentTime, duration);
	$(".music_progress_time").text(timeStr);
})

// 格式化时间
function formatDate(currentTime, duration){
	var endMin = parseInt(duration / 60); // 分钟
	var endSec = parseInt(duration % 60); // 秒钟
	if(endMin < 10){
		endMin = "0" + endMin;
	}
	if (endSec < 10) {
		endSec = "0" + endSec;
	}
	var startMin = parseInt(currentTime / 60);
	var startSec = parseInt(currentTime % 60);
	if (startMin < 10) {
		startMin = "0" + startMin;
	}
	if (startSec < 10) {
		startSec = "0" + startSec;
	}
	return startMin + ":" + startSec + " / " + endMin + ":" + endSec ;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
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); // 分钟
	var endSec = parseInt(duration % 60); // 秒钟
	if (endMin < 10) {
		endMin = "0" + endMin;
	}
	if (endSec < 10) {
		endSec = "0" + endSec;
	}
	var startMin = parseInt(currentTime / 60);
	var startSec = parseInt(currentTime % 60);
	if (startMin < 10) {
		startMin = "0" + startMin;
	}
	if (startSec < 10) {
		startSec = "0" + startSec;
	}
	return (startMin + ":" + startSec + " / " + endMin + ":" + endSec);
}

// 9.监听播放的进度
player.musicTimeUpdate(function (currentTime, duration, timeStr){
	$(".music_progress_time").text(timeStr);
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

声音控制

声音图标的控制

// 声音开关切换
musicVoiceSeekTo: function (value){
	// 取值范围是 0-1
	this.audio.volume = value;
}

// 10.监听声音按钮的点击
$(".music_voice_icon").click(function(){
	// 切换图标
	$(this).toggleClass("music_voice_icon1");
	// 声音切换
	if ($(this).attr("class").indexOf("music_voice_icon1") != -1){
		// 声音关闭
		player.musicVoiceSeekTo(0);
	} else{
		player.musicVoiceSeekTo(1);
	}
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

声音进度条的控制

var $voiceBar = $(".music_voice_bar");
var $voiceLine = $(".music_voice_line");
var $voiceDot = $(".music_voice_dot");
var voiceProgress = new Progress($voiceBar, $voiceLine, $voiceDot);
voiceProgress.progressClick(function (value) {
	player.musicVoiceSeekTo(value);
});
voiceProgress.progressMove(function (value) {
	player.musicVoiceSeekTo(value);
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

bug

进度条可以拖拽出去,判断

歌词控制

歌词加载

loadLyric:function(callBack){
	var $this = this;
	$.ajax({
		url: $this.path,
		dataType: "text",
		success: function (data) {
			$this.parseLyric(data);
			callBack();
		},
		error: function (e) {
			console.log(e);
		}
	})
},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

歌词解析

parseLyric:function(data){
	var $this = this;
	var array = data.split("\n");
	var timeReg = /\[(\d*:\d*\.\d*)\]/;
	// 遍历取出每一条歌词
	$.each(array,function(index,ele){
		// 处理歌词
	    var lrc = ele.split("]")[1];
		// 排除没有歌词的
		if(lrc.length <= 1) return true;
		$this.lyrics.push(lrc);

		// 用正则表达式匹配时间 [00:00.92]
		var res = timeReg.exec(ele);
		if(res == null) return true;
		var timeStr = res[1]; // 00:00.92
		var res1 = timeStr.split(":");
		var min = parseInt(res1[0]) * 60; // 分钟 - 秒
		var sec = parseFloat(res1[1]); // 秒
		var time = parseFloat(Number(min + sec).toFixed(2));// 保留两位小数
		$this.times.push(time);
	})
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

根据歌词创建歌词列表

// 3.初始化歌词信息
function initLyricInfo(music){
	var lyric = new Lyric(music.link_lrc);
	var $lyricContainer = $(".song_lyric");
	lyric.loadLyric(function(){
		// 创建歌词列表
		$.each(lyric.lyrics,function(index,ele){
			var $item = $("<li>"+ ele +"</li>");
			$lyricContainer.append($item);
		})
	});
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
'
运行

歌词同步和滚动

监听当前正在播放音乐的播放进度,
拿到当前播放的时间传给歌词对象,
利用当前播放时间和保存的时间匹配,
把匹配到的索引返回,
高亮对应的歌词滚动到对应的位置,
在点击子菜单播放按钮的时候,切换歌词的信息,
切换歌词信息的时候,清空之前保存的信息

currentIndex:function(currentTime){
	if(currentTime >= this.times[0]){
		this.index ++;
		this.times.shift(); // 删除数组最前面的一个元素
	}
	return this.index;
}

// 8.监听播放的进度
player.musicTimeUpdate(function (currentTime, duration, timeStr){
	// 实现歌词同步
	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)
	})
})

// 3.监听子菜单播放按钮的点击
$(".content_list").delegate(".list_menu_play", "click", function () {
	// 3.7 切换歌词信息
	initLyricInfo($music.get(0).music);
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27