<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>
* {
margin: 0;
padding: 0;
}
.header {
width: 100%;
height: 45px;
background: red;
}
.header .logo {
float: left;
margin-left: 20px;
opacity: 0.5;
}
.header .logo:hover {
opacity: 1;
}
.header .logo a {
display: inline-block;
width: 78px;
height: 21px;
background: url("../images/player_logo.png") no-repeat 0 0;
}
.header .register {
float: right;
line-height: 25px;
}
.header .register li {
list-style: none;
float: left;
margin-right: 20px;
color: #fff;
opacity: 0.5;
cursor: pointer;
}
.header .register li:hover {
opacity: 1;
}
.content {
width: 100%;
height: 460px;
background: blue;
}
.content .content_in {
width: 1200px;
height: 100%;
background: deeppink;
margin: 0 auto;
}
.footer {
width: 100%;
height: 60px;
background: green;
position: absolute;
bottom: 0;
left: 0;
}
.footer .footer_in {
width: 1200px;
height: 100%;
background: plum;
margin: 0 auto;
}
工具条使用span作为按钮,里边为图片加文字。
<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>
.content .content_in .content_left {
float: left;
width: 800px;
height: 100%;
background: pink;
}
.content_left .content_toolbar {
width: 100%;
height: 40px;
background: #000;
}
.content_toolbar span {
display: inline-block;
width: 122px;
height: 100%;
line-height: 40px;
text-align: center;
box-sizing: border-box;
border: 1px solid #fff;
color: #fff;
opacity: 0.5;
cursor: pointer;
}
.content_toolbar span:hover {
opacity: 1;
}
.content_toolbar span i {
display: inline-block;
width: 18px;
height: 18px;
background: url("../images/icon_sprite.png") no-repeat;
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;
}
歌曲列表可以视作逐行的列表,第一行为标题,下边为歌曲。
<div class="content_left">
<div class="content_list">
<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>
<li class="list_music">
<div class="list_check"><i></i></div>
<div class="list_number">1</div>
<div class="list_name">哈哈哈</div>
<div class="list_singer">TZK</div>
<div class="list_time">03:17</div>
</li>
</ul>
</div>
</div>
/* TAG 播放列表布局 */
.content_list li {
list-style: none;
width: 100%;
height: 50px;
background: orangered;
border: 1px solid rgba(255, 255, 255, 0.5);
box-sizing: border-box;
}
.content_list li div {
float: left;
color: #fff;
text-align: 50px;
opacity: 0.5;
}
.content_list .list_check {
width: 50px;
height: 100%;
background: #000;
text-align: center;
}
.content_list .list_check i {
display: inline-block;
width: 14px;
height: 14px;
border: 1px solid #000;
}
.content_list .list_number {
width: 20px;
height: 100%;
background: green;
}
.content_list .list_name {
width: 50%;
height: 100%;
background: #ccc;
}
.content_list .list_singer {
width: 20%;
height: 100%;
background: pink;
}
<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">TZK</div>
<div class="list_time">
<span>04:12</span>
<a href="javascript:;" title="删除"></a>
</div>
</li>
.list_name .list_menu {
margin-top: 5px;
float: right;
margin-right: 20px;
display: none;
}
.list_name .list_menu a {
display: inline-block;
width: 36px;
height: 36px;
background: url("../images/icon_list_menu.png") no-repeat 0 0;
}
.list_name .list_menu a:nth-child(1) {
background-position: -120px 0;
}
.list_name .list_menu a:nth-child(2) {
background-position: -120px -80px;
}
.list_name .list_menu a:nth-child(3) {
background-position: -120px -120px;
}
.list_name .list_menu a:nth-child(4) {
background-position: -120px -40px;
}
.content_list .list_time a {
display: inline-block;
width: 36px;
height: 36px;
background: url("../images/icon_list_menu.png") no-repeat -120px -160px;
float: left;
margin-top: 5px;
display: none;
}
$(function () {
// 1. 监听歌曲的移入移出事件
$(".list_music").hover(
function () {
// 显示子菜单
$(this).find(".list_menu").stop().fadeIn(100);
$(this).find(".list_time a").stop().fadeIn(100);
// 隐藏时长
$(this).find(".list_time span").stop().fadeOut(100);
},
function () {
// 隐藏子菜单
$(this).find(".list_menu").stop().fadeOut(100);
$(this).find(".list_time a").stop().fadeOut(100);
// 显示时长
$(this).find(".list_time span").stop().fadeIn(100);
}
);
// 2. 监听复选框的点击事件
$(".list_check").click(function () {
$(this).toggleClass("list_checked");
});
});
自定义滚动条使用了一个jQuery插件jQuery custom content scroller。利用这个插件可以轻松设置滚动条样式。
mCustomScrollbar()
方法
$(".content_list").mCustomScrollbar();data-mcs-theme="dark"
<div class="content_list" data-mcs-theme='minimal-dark'></div>根据图中所示,可以将滚动条的宽度增加。 /* 滚动条 */ ._mCS_1 .mCSB_scrollTools .mCSB_dragger_bar { width: 8px; }
<div class="content_right">
<div class="song_info">
<a href="javascript;;" class="song_info_pic">
<img src="images/lnj.jpg" alt="">
</a>
<div class="song_info_name">歌曲名称:
<a href="javascript:;">xiaokang</a>
</div>
<div class="song_info_singer">歌手名:
<a href="javascript:;">xiaokang</a>
</div>
<div class="song_info_ablum">专辑名:
<a href="javascript:;">xiaokang</a>
</div>
</div>
<ul class="song_lyric">
<li class="cur">第一条歌词</li>
<li>第二条歌词</li>
</ul>
</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("../images/album_cover_player.png") no-repeat 0 0;
width: 201px;
height: 180px;
text-align: left;
}
.song_info_pic img {
width: 180px;
height: 180px;
}
.song_info div a {
text-decoration: none;
color: #fff;
opacity: 0.5;
}
.song_info div a:hover {
opacity: 1;
}
.content_right .song_lyric {
background: gray;
text-align: center;
margin-top: 30px;
}
.content_right .song_lyric li {
list-style: none;
line-height: 30px;
color: rgba(255, 255, 255, 0.5);
font-weight: bold;
}
.content_right .song_lyric .cur {
color: #31c27c;
}
进度条可大致分为四部分
<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>
<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"></div>
</div>
.footer_in a {
display: inline-block;
text-decoration: none;
color: #fff;
background: url("../images/player.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;
}
.footer_in .music_next {
width: 19px;
height: 20px;
background-position: 0 -52px;
}
.footer_in .music_progress_info {
display: inline-block;
width: 670px;
height: 40px;
background-color: red;
}
.footer_in .music_mode {
width: 26px;
height: 25px;
background-position: 0px -205px;
}
.footer_in .music_fav {
width: 24px;
height: 21px;
background-position: 0px -96px;
}
.footer_in .music_down {
width: 22px;
height: 21px;
background-position: 0px -120px;
}
.footer_in .music_comment {
width: 24px;
height: 24px;
background-position: 0px -400px;
}
.footer_in .music_only {
width: 74px;
height: 27px;
background-position: 0px -281px;
}
.footer_in .music_voice_info {
display: inline-block;
width: 100px;
background: green;
height: 40px;
}
<div class="music_progress_info">
<div class="music_progress_top">
<span class="music_progress_name">666/666</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>
/* 歌曲进度条 */
.footer_in .music_progress_info {
display: inline-block;
width: 670px;
height: 40px;
background-color: red;
}
.music_progress_info .music_progress_top {
width: 100%;
height: 30px;
line-height: 30px;
background: #000000;
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;
}
.music_progress_bar .music_progress_line {
width: 100%;
height: 100%;
background: #ffffff;
}
.music_progress_bar .music_progress_dot {
width: 14px;
height: 14px;
border-radius: 50%;
background: #fff;
position: relative;
top: -5px;
left: 100px;
cursor: pointer;
}
/* 音量控制 */
.footer_in .music_voice_info {
display: inline-block;
width: 100px;
background: green;
height: 40px;
position: relative;
}
.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 {
width: 50px;
height: 100%;
background: #ffffff;
}
.music_voice_bar .music_voice_dot {
width: 14px;
height: 14px;
border-radius: 50%;
background: #ffffff;
position: absolute;
top: -5px;
left: 50px;
}
.footer {
height: 80px;
}
.footer_in .music_play {
vertical-align: -5px;
}
.footer_in .music_progress_info {
top: 10px;
}
.footer_in .music_voice_info {
top: 10px;
}
/* 播放按钮点击 */
.footer_in .music_play2 {
background-position: -30px 0;
}
/* 循环模式样式切换 */
.footer_in .music_mode2 {
width: 23px;
height: 20px;
background-position: 0px -260px;
}
.footer_in .music_mode3 {
width: 25px;
height: 19px;
background-position: 0px -74px;
}
.footer_in .music_mode4 {
width: 26px;
height: 25px;
background-position: 0px -232px;
}
/* 喜欢按钮 */
.footer_in .music_fav2 {
background-position: -30px -96px;
}
/* 纯净模式 */
.footer_in .music_only2 {
background-position: 0px -310px;
}
模糊背景通过使用一张图加一个淡灰色的蒙版即可。
<div class="footer"></div>
<div class="mask_bg"></div>
<div class="mask"></div>
/* 背景设置 */
.mask_bg {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: url("../images/lnj.jpg") no-repeat 0 0;
background-size: cover;
z-index: -2;
filter: blur(100px);
}
.mask {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: -1;
background: rgba(0, 0, 0, 0.35);
}
加载歌曲使用了jQuery得Ajax方法。通过一个json文件获取歌曲的相关信息。
// 3. 加载歌曲列表
function getPlayerList() {
$.ajax({
url: "./source/musiclist.json",
dataType: "json",
success: function (data) {
// 3.1 遍历获取到的数据创建每一条音乐
var $musicList = $(".content_list ul");
$.each(data, function (index, ele) {
var $item = createMusicItem(index, ele);
$musicList.append($item);
});
},
error: function (e) {
console.log(e);
},
});
}
getPlayerList();
// 创建一条音乐的方法
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="播放"></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="删除"></a></div></li>'
);
return $item;
}
由于音乐列表改成了js动态创建,那么就会导致曾经绑定的事件失效,因此需要修改为事件委托方式。
// 1. 监听歌曲的移入移出事件
$(".content_list").delegate(".list_music", "mouseenter", function () {
// 显示子菜单
$(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);
});
// 2. 监听复选框的点击事件
$(".content_list").delegate(".list_check", "click", function () {
$(this).toggleClass("list_checked");
});
为此按钮添加事件同样需要以事件委托的方式。当点击后会发生两件事:
// 3. 添加子菜单播放按钮的监听
var $musicPlay = $(".music_play");
$(".content_list").delegate(".list_menu_play", "click", function () {
// 3.1 切换播放的图标
$(this).toggleClass("list_menu_play2");
// 3.2 复原其他的播放图标
$(this)
.parents(".list_music")
.siblings()
.find(".list_menu_play")
.removeClass("list_menu_play2");
// 3.3 同步底部播放按钮
if ($(this).attr("class").indexOf("list_menu_play2") != -1) {
// 当前是播放状态
$musicPlay.addClass("music_play2");
} else {
$musicPlay.removeClass("music_play2");
}
});
要想控制单个,必须设置时对单个设置,而不是全部,因此css部分需要微调。
.content_list li div {
color: rgba(255, 255, 255, 0.5);
}
.content_list .list_check i {
opacity: 0.5;
}
.content_list .list_checked i {
opacity: 1;
}
.list_name .list_menu a {
opacity: 0.5;
}
.list_name .list_menu a:hover {
opacity: 1;
}
.content_list .list_time a {
opacity: 0.5;
}
.content_list .list_time a:hover {
opacity: 1;
}
将css修改完成后,接下来就是在JavaScript绑定的事件中进行修改了。
// 3.3 同步底部播放按钮
if ($(this).attr("class").indexOf("list_menu_play2") != -1) {
// 当前是播放状态
$musicPlay.addClass("music_play2");
// 让文字高亮
$(this).parents(".list_music").find("div").css("color", "#fff");
} else {
$musicPlay.removeClass("music_play2");
// 让文字不高亮
$(this)
.parents(".list_music")
.find("div")
.css("color", "rgba(255,255,255,0.5)");
}
动画采用图片的方式实现。当点击时,因此文字,并且显示图片。并作一些排他设置。
$(".content_list").delegate(".list_menu_play", "click", function () {
var $item = $(this).parents(".list_music");
// 3.1 切换播放的图标
$(this).toggleClass("list_menu_play2");
// 3.2 复原其他的播放图标
$(this)
.parents(".list_music")
.siblings()
.find(".list_menu_play")
.removeClass("list_menu_play2");
// 3.3 同步底部播放按钮
if ($(this).attr("class").indexOf("list_menu_play2") != -1) {
// 当前是播放状态
$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");
});
.content_list .list_number2 {
color: transparent !important;
background: url("../images/wave.gif") no-repeat 0 0;
}
(function (window) {
function Player() {
return new Player.prototype.init();
}
Player.prototype = {
constructor: Player,
init: function () {},
};
Player.prototype.init.prototype = Player.prototype;
window.Player = Player;
})(window);
init()
方法
也就是通过init()
创建类Player
,并定义init
方法Player
原型上的init
方法的原型指向Player
的原型audio
标签,用于播放音乐Player
对象,并且传入audio
对象index
和music
信息Player.prototype = { currentIndex: -1, 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; } }, };
底部播放暂停的逻辑:
$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"); });对象的preIndex
与nextIndex
方法用于处理索引。
preIndex: function () { var index = this.currentIndex - 1; if (index < 0) { index = this.musicList.length - 1; } return index; }, nextIndex: function () { var index = this.currentIndex + 1; if (index > this.musicList.length - 1) { index = 0; } return index; },
删除数据时需要注意的就是前台删除数据后,后台也无需保存数据。并且需要对标签保存的数据进行重新排序
// 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);
});
});
删除后需要注意删除的数据是否是正在播放的音乐的前边,如果是需要将索引-1。否则会出现下一曲跳歌的现象。
changeMusic: function (index) {
// 删除对应的数据
this.musicList.splice(index, 1);
//判断当前删除的是否是正在播放的前面的音乐
if (index < this.currentIndex) {
this.currentIndex = this.currentIndex - 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 + '")');
}
$.ajax({
success: function (data) {
initMusicInfo(data[0]);
},
});
$(".content_list").delegate(".list_menu_play", "click", function () {
// 3.6 切换歌曲信息
initMusicInfo($item.get(0).music);
});
progressClick: function () {
var $this = this; //this 是progress
// 监听背景的点击
this.$progressBar.click(function (event) {
// 获取背景距离窗口默认的位置
var normalLeft = $(this).offset().left;
// 获取点击的位置距离窗口默认的位置
var eventLeft = event.pageX;
// 设置前景的宽度
$this.$progressLine.css("width", eventLeft - normalLeft);
$this.$progressDot.css("left", eventLeft - normalLeft);
});
},
mousemove
方法监听,但必须在鼠标按下后监听mousemove
事件即可progressMove: function () {
var $this = this;
// 1. 监听的鼠标的按下事件
this.$progressBar.mousedown(function () {
// 获取背景距离窗口默认的位置
var normalLeft = $(this).offset().left;
// 2. 监听鼠标的移动事件
$(document).mousemove(function () {
// 获取点击的位置距离窗口默认的位置
var eventLeft = event.pageX;
// 设置前景的宽度
$this.$progressLine.css("width", eventLeft - normalLeft);
$this.$progressDot.css("left", eventLeft - normalLeft);
});
});
// 3. 监听鼠标的抬起事件
$(document).mouseup(function () {
$(document).off("mousemove");
});
},
音乐时间同步
通过timeupdate
事件监听是否播放,正在播放时,会不断触发这个事件。在事件内部通过duration
与currentTime
获取当前时长和总时长。
于是可以在player
类中新增加方法
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;
},
在我们的index.js
中只需要调用这个方法即可。
// 8. 监听播放的进度
player.musicTimeUpdate(function (currentTime, duration, timeStr) {
// 同步时间
$(".music_progress_time").text(timeStr);
});
进度条同步
同样的为进度条新增方法setProgress
setProgress: function (value) {
if (value < 0 || value > 100) return;
this.$progressLine.css({
width: value + "%",
});
this.$progressDot.css({
left: value + "%",
});
},
这样完成后,在主函数中计算出当前时间所占比例即可调用此方法进行设置。
// 8. 监听播放的进度
player.musicTimeUpdate(function (currentTime, duration, timeStr) {
// 同步进度条
// 计算播放比例
var value = (currentTime / duration) * 100;
progress.setProgress(value);
});
因为使用了百分比进行修改元素,那么css的定位方式也需要修改一下:
.music_progress_info .music_progress_bar {
position: relative;
}
.music_progress_bar .music_progress_dot {
position: absolute;
}
实现思路:
progress.progressClick(function (value) {
player.musicSeekTo(value);
});
progress.progressMove(function (value) {
player.musicSeekTo(value);
});
musicSeekTo: function (value) {
this.audio.currentTime = this.audio.duration * value;
},
为了实现拖拽时声音能够继续播放,因此将设置的方法改到mouseup事件中
progressMove: function (callBack) {
var $this = this;
var normalLeft, eventLeft;
// 1. 监听的鼠标的按下事件
this.$progressBar.mousedown(function () {
// 获取背景距离窗口默认的位置
normalLeft = $(this).offset().left;
$this.isMove = true;
// 2. 监听鼠标的移动事件
$(document).mousemove(function () {
// 获取点击的位置距离窗口默认的位置
eventLeft = event.pageX;
// 设置前景的宽度
$this.$progressLine.css("width", eventLeft - normalLeft);
$this.$progressDot.css("left", eventLeft - normalLeft);
});
});
// 3. 监听鼠标的抬起事件
$(document).mouseup(function () {
$(document).off("mousemove");
$this.isMove = false;
// 计算进度条的比例
var value = (eventLeft - normalLeft) / $this.$progressBar.width();
callBack(value);
});
},
声音控制与进度条控制几乎一致
var $voiceBar = $(".music_voice_bar");
var $voiceLine = $(".music_voice_line");
var $voiceDot = $(".music_voice_dot");
voicePregress = Progress($voiceBar, $voiceLine, $voiceDot);
voicePregress.progressClick(function (value) {
player.musicVoiceSeekTo(value);
});
voicePregress.progressMove(function (value) {
player.musicVoiceSeekTo(value);
});
}
接下来为player
类新增方法即可。
musicVoiceSeekTo: function (value) {
// 取值0~1
this.audio.volume = value;
},
解析创建一个新的类用于解析歌词。
(function (window) {
function Lyric(path) {
return new Lyric.prototype.init(path);
}
Lyric.prototype = {
constructor: Lyric,
init: function (path) {
this.path = path;
},
// 保存匹配的时间
times: [],
// 保存匹配的歌词
lyrics: [],
loadLyric: function (callBack) {
var $this = this;
$.ajax({
url: $this.path,
dataType: "text",
success: function (data) {
$this.pareLyric(data);
callBack();
},
error: function (e) {},
});
},
// 解析歌词的方法
pareLyric: 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);
var res = timeReg.exec(ele);
if (res == null) return true;
var timeStr = res[1];
var res2 = timeStr.split(":");
var min = parseInt(res2[0]) * 60;
var sec = parseFloat(res2[1]);
var time = parseFloat(Number(min + sec).toFixed(2));
$this.times.push(time);
});
console.log($this.times);
console.log($this.lyrics);
},
};
Lyric.prototype.init.prototype = Lyric.prototype;
window.Lyric = Lyric;
})(window);
接下来只需要在自己的JavaScript中初始化这个类并且调用方法即可。
// 3. 初始化歌词信息
function initMusicLyric(music) {
var lyric = new Lyric(music.link_lrc);
var $lryicContainer = $(".song_lyric");
lyric.loadLyric(function () {
// 创建歌词列表
$.each(lyric.lyrics, function (index, ele) {
var $item = $("<li>" + ele + "</li>");
$lryicContainer.append($item);
});
});
}
创建好了之后,还需要对样式进行一点点小的修改
.content_right .song_lyric {
height: 150px;
overflow: hidden;
}
歌词同步需要在监听播放的进度中去设置
// 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,
});
});
因为使用了margin-top
滚动歌词,那么需要将html也该动。
<div class="song_lyric_container">
<ul class="song_lyric"></ul>
</div>
为了实现切换歌曲时,歌词也可以切换,也需要在切换歌曲时将保存的歌曲信息也切换。
loadLyric: function (callBack) {
$this.times = [];
$this.lyrics = [];
},
function initMusicLyric(music) {
$lryicContainer.html("");
}
$(".content_list").delegate(".list_menu_play", "click", function () {
// 3.7切换歌词信息
initMusicLyric($item.get(0).music);
});