项目资料 基本框架及顶部布局
1 2 3 4 5 6 7 8 9 10 11 12 13 <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 >
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 * { 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作为按钮,里边为图片加文字。
1 2 3 4 5 6 7 8 9 10 11 <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 >
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 .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 ; }
歌曲列表
歌曲列表可以视作逐行的列表,第一行为标题,下边为歌曲。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <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 >
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 .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; }
完善播放列表
选择框
伪选择框,使用图片,当被点击时,切换图片
鼠标悬停的图标
使用a标签加背景图即可。使用jQuery监听鼠标的移入移出事件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <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 >
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 .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; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 $(function ( ) { $(".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 ); } ); $(".list_check" ).click(function ( ) { $(this ).toggleClass("list_checked" ); }); });
自定义滚动条
自定义滚动条使用了一个jQuery插件jQuery custom content scroller 。利用这个插件可以轻松设置滚动条样式。
引入CSS文件
在jQuery下方引入JS文件
为需要添加的元素调用mCustomScrollbar()
方法
1 $(".content_list" ).mCustomScrollbar();
为该元素添加自定义属性data-mcs-theme="dark"
1 <div class ="content_list" data-mcs-theme ='minimal-dark' > </div >
小细节(修改其默认样式)
根据图中所示,可以将滚动条的宽度增加。
1 2 3 4 ._mCS_1 .mCSB_scrollTools .mCSB_dragger_bar { width : 8px ;}
音乐歌曲信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <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 >
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 .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 ; }
底部结构 基本结构
进度条可大致分为四部分
图标
使用a标签加背景图即可
歌曲进度条(红色区域)
因为此区域需包含进度条及歌曲名称、时间等信息。因此使用div作为布局
音量部分(绿色区域)
此部分包含图标及一个拖动条,因此也使用div作为盒子进行布局。
1 2 3 4 5 6 7 8 9 10 11 12 <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 >
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 .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 ; }
进度条
歌曲部分的结构
信息部分
两个span元素即可
进度条
一种通用的结构。三层结构分别表示背景、前景、圆。
1 2 3 4 5 <div class ="music_progress_bar" > <div class ="music_progress_line" > <div class ="music_progress_dot" > </div > </div > </div >
音量部分
与歌曲信息的进度条同理,图标同样使用a标签与图片结合。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <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 >
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 .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 ; }
底部微调完善
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 .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 ; }
高斯模糊背景
模糊背景通过使用一张图加一个淡灰色的蒙版即可。
1 2 3 <div class ="footer" > </div > <div class ="mask_bg" > </div > <div class ="mask" > </div >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 .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文件获取歌曲的相关信息。
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 function getPlayerList ( ) { $.ajax({ url: "./source/musiclist.json" , dataType: "json" , success: function (data ) { 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 $(".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 ); }); $(".content_list" ).delegate(".list_check" , "click" , function ( ) { $(this ).toggleClass("list_checked" ); });
音乐播放图标切换
为此按钮添加事件同样需要以事件委托的方式。当点击后会发生两件事:
将其他播放按钮改为暂停状态 将底部播放按钮修改 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 var $musicPlay = $(".music_play" );$(".content_list" ).delegate(".list_menu_play" , "click" , function ( ) { $(this ).toggleClass("list_menu_play2" ); $(this ) .parents(".list_music" ) .siblings() .find(".list_menu_play" ) .removeClass("list_menu_play2" ); if ($(this ).attr("class" ).indexOf("list_menu_play2" ) != -1 ) { $musicPlay.addClass("music_play2" ); } else { $musicPlay.removeClass("music_play2" ); } });
音乐播放状态切换
要想控制单个,必须设置时对单个设置,而不是全部,因此css部分需要微调。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 .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绑定的事件中进行修改了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 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)" ); }
序号动画
动画采用图片的方式实现。当点击时,因此文字,并且显示图片。并作一些排他设置。
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 $(".content_list" ).delegate(".list_menu_play" , "click" , function ( ) { var $item = $(this ).parents(".list_music" ); $(this ).toggleClass("list_menu_play2" ); $(this ) .parents(".list_music" ) .siblings() .find(".list_menu_play" ) .removeClass("list_menu_play2" ); 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)" ); } $item.find(".list_number" ).toggleClass("list_number2" ); $item.siblings().find(".list_number" ).removeClass("list_number2" ); });
1 2 3 4 .content_list .list_number2 { color : transparent !important ; background : url ("../images/wave.gif" ) no-repeat 0 0 ; }
播放工具类封装
1 2 3 4 5 6 7 8 9 10 11 12 (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
的原型
将这个对象开放给window
音乐的播放暂停在HTML页面插入一个audio
标签,用于播放音乐
引入player工具库
实例化一个Player
对象,并且传入audio
对象
当按钮被点击时,调用播放音乐的方法
实现播放/暂停音乐的方法
当创建音乐标签时,在标签中保存索引及音乐信息
1 2 3 4 5 6 7 function createMusicItem (index, music ) { var $item = $(...); $item.get(0 ).index = index; $item.get(0 ).music = music; return $item; }
接收两个参数,分别为index
和music
信息
定义一个遍历,用于记录当前索引
判断是否为同一首音乐
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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; } }, };
底部播放/暂停/上一首/下一首底部播放暂停的逻辑:
播放暂停
1 2 3 4 5 6 7 8 9 10 11 12 13 $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" ); } });
上一首/下一首
1 2 3 4 5 6 7 8 9 10 11 12 13 14 $(".music_pre" ).click(function ( ) { $(".list_music" ) .eq(player.preIndex()) .find(".list_menu_play" ) .trigger("click" ); }); $(".music_next" ).click(function ( ) { $(".list_music" ) .eq(player.nextIndex()) .find(".list_menu_play" ) .trigger("click" ); });
对象的preIndex
与nextIndex
方法用于处理索引。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 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; },
删除歌曲删除数据时需要注意的就是前台删除数据后,后台也无需保存数据。并且需要对标签保存的数据进行重新排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 $(".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。否则会出现下一曲跳歌的现象。
1 2 3 4 5 6 7 8 changeMusic: function (index ) { this .musicList.splice(index, 1 ); if (index < this .currentIndex) { this .currentIndex = this .currentIndex - 1 ; } },
切换歌曲信息
更换歌曲信息涉及到的基本信息包括:
右侧信息栏
底部控制条的名称、时间
实现这个这个功能也很简单,只是一些元素的替换。调用位置有两处
第一次获取歌曲时(成功)的回调
初始化列表的第一个音乐
当点击其他歌曲时
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 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 ( ) { initMusicInfo($item.get(0 ).music); });
进度条的实现
获取被点击位置距离窗口的位置 获取默认距离窗口的位置 被点击的位置减去默认距离窗口的位置 点击进度条时,调整小圆点以及前景色的位置 1 2 3 4 5 6 7 8 9 10 11 12 13 progressClick: function ( ) { var $this = this ; 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
事件即可 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 progressMove: function ( ) { var $this = this ; this .$progressBar.mousedown(function ( ) { var normalLeft = $(this ).offset().left; $(document ).mousemove(function ( ) { var eventLeft = event.pageX; $this.$progressLine.css("width" , eventLeft - normalLeft); $this.$progressDot.css("left" , eventLeft - normalLeft); }); }); $(document ).mouseup(function ( ) { $(document ).off("mousemove" ); }); },
音乐时间、进度条同步
音乐时间同步
通过timeupdate
事件监听是否播放,正在播放时,会不断触发这个事件。在事件内部通过duration
与currentTime
获取当前时长和总时长。
于是可以在player
类中新增加方法
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 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
中只需要调用这个方法即可。
1 2 3 4 5 player.musicTimeUpdate(function (currentTime, duration, timeStr ) { $(".music_progress_time" ).text(timeStr); });
进度条同步
同样的为进度条新增方法setProgress
1 2 3 4 5 6 7 8 9 setProgress: function (value ) { if (value < 0 || value > 100 ) return ; this .$progressLine.css({ width: value + "%" , }); this .$progressDot.css({ left: value + "%" , }); },
这样完成后,在主函数中计算出当前时间所占比例即可调用此方法进行设置。
1 2 3 4 5 6 7 player.musicTimeUpdate(function (currentTime, duration, timeStr ) { var value = (currentTime / duration) * 100 ; progress.setProgress(value); });
因为使用了百分比进行修改元素,那么css的定位方式也需要修改一下:
1 2 3 4 5 6 .music_progress_info .music_progress_bar { position : relative; } .music_progress_bar .music_progress_dot { position : absolute; }
点击进度条与歌曲同步实现思路:
计算出总时长除以已播放时长的比例 将歌曲进度设置为歌曲时长乘以上一步的比例 1 2 3 4 5 6 progress.progressClick(function (value ) { player.musicSeekTo(value); }); progress.progressMove(function (value ) { player.musicSeekTo(value); });
1 2 3 musicSeekTo: function (value ) { this .audio.currentTime = this .audio.duration * value; },
为了实现拖拽时声音能够继续播放,因此将设置的方法改到mouseup事件中
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 progressMove: function (callBack ) { var $this = this ; var normalLeft, eventLeft; this .$progressBar.mousedown(function ( ) { normalLeft = $(this ).offset().left; $this.isMove = true ; $(document ).mousemove(function ( ) { eventLeft = event.pageX; $this.$progressLine.css("width" , eventLeft - normalLeft); $this.$progressDot.css("left" , eventLeft - normalLeft); }); }); $(document ).mouseup(function ( ) { $(document ).off("mousemove" ); $this.isMove = false ; var value = (eventLeft - normalLeft) / $this.$progressBar.width(); callBack(value); }); },
声音控制声音控制与进度条控制几乎一致
1 2 3 4 5 6 7 8 9 10 11 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
类新增方法即可。
1 2 3 4 musicVoiceSeekTo: function (value ) { this .audio.volume = value; },
bug修复音乐进度的跳转应为一个正常的数字
1 2 3 4 musicSeekTo: function (value ) { if (isNaN (value)) return ; this .audio.currentTime = this .audio.duration * value; },
音量同理且音量范围为0~1
1 2 3 4 5 6 musicVoiceSeekTo: function (value ) { if (isNaN (value)) return ; if (value < 0 || value > 1 ) return ; this .audio.volume = value; },
拖拽超出范围
1 2 3 4 5 6 7 8 9 10 11 12 13 progressMove: function (callBack ) { var barWidth = this .$progressBar.width(); this .$progressBar.mousedown(function ( ) { $(document ).mousemove(function ( ) { var offset = eventLeft - normalLeft; if (offset >= 0 && offset <= barWidth) { $this.$progressLine.css("width" , eventLeft - normalLeft); $this.$progressDot.css("left" , eventLeft - normalLeft); } }); });
歌词设置 歌词解析并且加载(创建)
解析创建一个新的类用于解析歌词。
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 (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中初始化这个类并且调用方法即可。
1 2 3 4 5 6 7 8 9 10 11 12 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); }); }); }
创建好了之后,还需要对样式进行一点点小的修改
1 2 3 4 .content_right .song_lyric { height : 150px ; overflow : hidden; }
歌词同步歌词同步需要在监听播放的进度中去设置
1 2 3 4 5 6 7 8 9 10 11 12 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也该动。
1 2 3 <div class ="song_lyric_container" > <ul class ="song_lyric" > </ul > </div >
为了实现切换歌曲时,歌词也可以切换,也需要在切换歌曲时将保存的歌曲信息也切换。
1 2 3 4 loadLyric: function (callBack ) { $this.times = []; $this.lyrics = []; },
1 2 3 4 5 6 7 function initMusicLyric (music ) { $lryicContainer.html("" ); } $(".content_list" ).delegate(".list_menu_play" , "click" , function ( ) { initMusicLyric($item.get(0 ).music); });