从零玩转jQuery之项目开发(QQ音乐播放器)

QQ音乐播放器项目

大体效果如下:
在这里插入图片描述

HTML结构分析:
在这里插入图片描述

一、页面布局

1、首先来看下HTML大体结构:

<div class="header"></div>
<div class="content">
    <div class="content-in">
        <div class="content-left"></div>
        <div class="content-right"></div>
    </div>
</div>
<div class="footer">
    <div class="footer-in"></div>
</div>

效果如下:
在这里插入图片描述

2、完成页面头部

HTML代码:

<div class="header">
   <!-- logo -->
   <h1 class="logo">
       <a href="#"></a>
   </h1>
   <!-- 登录注册按钮 -->
   <ul class="register">
       <li>登录</li>
       <li>注册</li>
   </ul>
</div>

css样式代码:

.header {
    width: 100%;
    height: 45px;
}

.header .logo {
    float: left;
    margin-left: 20px;
    opacity: .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 {
    line-height: 45px;
    list-style: none;
    float: right;
}

.header .register li {
    float: left;
    cursor: pointer;
    margin-right: 20px;
    color: #fff;
    opacity: .5;
}

.header .register li:hover {
    opacity: 1;
}

效果如下:
在这里插入图片描述

3、完成内容区的菜单部分

在这里插入图片描述
HTML结构如下:

<!-- 作为菜单标签 -->
<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>

css样式如下:

.content .content-in .content-left .content-toolbar {
    width: 100%;
    height: 40px;

}

.content .content-in .content-left .content-toolbar span {
    display: inline-block;
    width: 122px;
    height: 100%;
    border: 1px solid #fff;
    box-sizing: border-box;
    text-align: center;
    line-height: 40px;
    border-radius: 5px;
    opacity: .5;
    color: #fff;
    font-size: 14px;
}

.content .content-in .content-left .content-toolbar span:hover {
    opacity: 1;
}

.content .content-in .content-left .content-toolbar span i {
    width: 18px;
    height: 18px;
    display: inline-block;
    background: url(../images/icon_sprite.png) no-repeat 0 0;
    vertical-align: -5px;
    margin-right: 9px;

}

.content .content-in .content-left .content-toolbar span:nth-child(1) i {
    background-position: -60px -20px;
}

.content .content-in .content-left .content-toolbar span:nth-child(2) i {
    background-position: -20px -20px;
}

.content .content-in .content-left .content-toolbar span:nth-child(3) i {
    background-position: -40px -240px;
}

.content .content-in .content-left .content-toolbar span:nth-child(4) i {
    background-position: -100px -20px;
}

.content .content-in .content-left .content-toolbar span:nth-child(5) i {
    background-position: -40px -300px;
}

4、完成歌曲列表布局

我们只完成第一行,因为除了第一行以外,其他的都是歌曲,后边通过js来动态创建

<!-- 作为歌曲菜单 -->
<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>

css样式如下:

.content .content-in .content-left .content-list {
    width: 100%;
    /* height: 760px; */
    height: 600px;
    overflow: auto;
    margin-top: 50px;
}

.content-list li {
    width: 775px;
    height: 50px;
    list-style: none;
    border-bottom: 1px solid rgba(255, 255, 255, .5);
    user-select: none;
}

.content-list div {
    float: left;
    line-height: 50px;
    /*opacity: .8;*/
    color: rgba(255, 255, 255, .5);
}

.content-list .list-check {
    width: 50px;
    height: 100%;
    text-align: center;
}

.content-list .list-check i {
    display: inline-block;
    width: 14px;
    height: 14px;
    border: 1px solid #fff;
    box-sizing: border-box;
    opacity: .5;
}

.content-list .list-checked i {
    background: url(../images/icon_sprite.png) no-repeat -60px -80px;

    opacity: 1;
}

.content-list .list-number {
    width: 20px;
    height: 100%;

}

.content-list .list-number2 {
    color: transparent !important;
    background: url("../images/wave.gif") no-repeat 0 center;

}

.content-list .list-name {
    width: 50%;
    height: 100%;
}

.content-list .list-music .list-name .list-menu {
    float: right;
    margin-top: 7px;
    margin-right: 10px;
    display: none;
}

.content-list .list-music .list-name .list-menu a {
    display: inline-block;
    width: 36px;
    height: 36px;
    background: url(../images/icon_list_menu.png) no-repeat 0 0;
    opacity: .5;
}

.content-list .list-music .list-name .list-menu a:hover {
    opacity: 1;
}

.content-list .list-music .list-name .list-menu a:nth-child(1) {
    background-position: -120px 0;
}

.content-list .list-music .list-name .list-menu a:nth-child(2) {
    background-position: -120px -80px;
}

.content-list .list-music .list-name .list-menu a:nth-child(3) {
    background-position: -120px -120px;
}

.content-list .list-music .list-name .list-menu a:nth-child(4) {
    background-position: -120px -40px;
}

.content-list .list-menu-play2 {
    background-position: -80px -200px !important;
}

.content-list .list-singer {
    width: 20%;
    height: 100%;
}

.content-list .list-time {
    width: 20%;
    height: 100%;
}

.content-list .list-music .list-time a {
    display: inline-block;
    width: 36px;
    height: 36px;
    background: url(../images/icon_list_menu.png) no-repeat 0 0;
    background-position: -120px -160px;
    float: left;
    margin-top: 7px;
    display: none;
    opacity: .5;
}

.content-list .list-music .list-time a:hover {
    opacity: 1;
}

5、自定义歌曲列表滚动条

  1. 首先下载一个jQuery插件:jQuery custom content scroller(http://manos.malihu.gr/jquery-custom-content-scroller/)
  2. 引入下载好的css文件
  3. 为需要添加的元素调用mCustomScrollbar()方法: $(".content_list").mCustomScrollbar();
  4. 为该元素添加自定义属性 data-mcs-theme=“dark”:<div class="content_list" data-mcs-theme='minimal-dark'></div>
  5. 可以设置滚动条的宽度:
    ._mCS_1 .mCSB_scrollTools .mCSB_dragger_bar { width: 8px; }

如图所示自定义滚动条设置完毕:
在这里插入图片描述

6、右边的歌曲信息与歌词布局

在这里插入图片描述
HTML结构如下:

<!-- 作为内容区的右边部分 -->
<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:;">海市蜃楼</a>
      </div>
      <div class="song-info-singer">歌手名:
          <a href="javascript:;">网络未知名歌手</a>
      </div>
      <div class="song-info-album">专辑名:
          <a href="javascript:;">未知名系列</a>
      </div>
  </div>
  <div class="song-lyric-container">
      <!-- 歌词 -->
      <ul class="song-lyric">
          <!-- 默认显示两条歌词 -->
      </ul>
  </div>
</div>

css样式如下:

.content-right {
    width: 400px;
    height: 100%;
    float: right;
    user-select: none;
}

.content-right .song-info {
    text-align: center;
    color: rgba(255, 255, 255, .5);
    line-height: 30px;
    cursor: pointer;
}

.content-right .song-info .song-info-pic {
    display: inline-block;
    width: 201px;
    height: 180px;
    text-align: left;
    background: url(../images/album_cover_player.png) no-repeat 0 0;
}

.song-info-pic img {
    width: 180px;
    height: 180px;
}

.content-right .song-info div a {
    text-decoration: none;
    color: #fff;
    opacity: .5;
}

.content-right .song-info div a:hover {
    opacity: 1;
}
.content-right .song-lyric-container {
    height: 300px;
    overflow: hidden;
    margin-top: 70px;
    /* background-color: rebeccapurple; */
}

.content-right .song-lyric {
    
    cursor: pointer;
    opacity: .7;
    list-style: none;
    text-align: center;
    line-height: 30px;
    /* font-weight: bold; */
    font-family: poppin,
        Tahoma,
        Arial,
        \5FAE\8F6F\96C5\9ED1,
        sans-serif;
    font-size: 15px;
}

.content-right .song-lyric .cur {
    color: #31c27c;

}

7、底部播放按钮部分

HTML结构:

<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">旧梦一场 - 阿悠悠</span>
             <span class="music-progress-time">00:00 / 05:30</span>
         </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-right">
             <!-- 音量进度条 -->
             <div class="music-voice-bar">
                 <div class="music-voice-line">
                     <div class="music-voice-dot"></div>
                 </div>
             </div>
         </div>
     </div>
 </div>

css样式:

.footer {
    width: 100%;
    height: 80px;
    position: absolute;
    bottom: 0;
}

.footer-in {
    width: 1200px;
    height: 100%;
    margin: auto;
    user-select: none;
}

.footer-in div {
    display: inline-block;
}

.footer-in a {
    display: inline-block;
    text-decoration: none;
    background: url(../images/player.png) no-repeat 0 0;
    margin-right: 40px;
}

.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 {
    width: 500px;
    height: 40px;
    margin-right: 40px;
}

.footer-in .music-progress-info .music-progress-top {
    width: 100%;
    height: 20px;
    line-height: 20px;
    color: #fff;
}

.footer-in .music-progress-info .music-progress-top .music-progress-name {
    float: left;
}

.footer-in .music-progress-info .music-progress-top .music-progress-time {
    float: right;
}

.footer-in .music-progress-info .music-progress-bar {
    width: 100%;
    height: 4px;
    background-color: rgba(255, 255, 255, .5);
    position: relative;
}

.footer-in .music-progress-info .music-progress-line {
    width: 0;
    height: 100%;
    background-color: #fff;
    float: left;
}

.footer-in .music-progress-info .music-progress-dot {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background-color: white;
    position: absolute;
    top: -5px;
    left: 0;
}

.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;
    margin-right: 20px;
}

.footer-in .music-only2 {
    background-position: 0 -310px;
}

.footer-in .music-voice-info {
    width: 93px;
    height: 24px;
}

.footer-in .music-voice-info .music-voice-icon {
    display: inline-block;
    width: 26px;
    height: 21px;
    background-position: 0 -144px;
    margin-right: 0;

}

.footer-in .music-voice-info .music-voice-icon2{
    background-position: 0 -182px;
}

.footer-in .music-voice-info .music-voice-right {
    width: 68%;
    height: 100%;
    float: right;
    margin-right: 0;
    margin-top: -3px;
}

.footer-in .music-voice-info .music-voice-bar {
    width: 100%;
    height: 4px;
    background-color: rgba(255, 255, 255, .5);
}

.footer-in .music-voice-info .music-voice-line {
    width: 100%;
    height: 100%;
    background-color: #fff;
    position: relative;
    float: left;
}

.footer-in .music-voice-info .music-voice-dot {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background-color: white;
    position: absolute;
    top: -5px;
    left: 100%;
}

8、高斯模糊背景设置

我们需要定义两div用来设置页面整体高斯模糊背景图像

<!-- 歌手音乐图片作为背景效果 -->
<div class="mask-bg"></div>
<!-- 灰色遮罩 -->
<div class="mask"></div>

有了这两元素大体上就可以设置我们的背景效果了。
css样式效果如下:

.mask-bg {
    z-index: -2;
    width: 100%;
    height: 100%;
    background: url(../images/lnj.jpg) no-repeat 0 0;
    background-size: cover;
    position: absolute;
    top: 0;
    left: 0;
    filter: blur(100px);
    /* 图片模糊设置 */
}

.mask {
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
    background: rgba(0, 0, 0, 0.35);
    z-index: -1;
}

注意点:

z-index 属性指定一个元素的堆叠顺序。
拥有更高堆叠顺序的元素总是会处于堆叠顺序较低的元素的前面。

到现在为止,静态页面已经布局完毕。

二、页面动态部分

为了后期的维护,我们需要单独为每个类型功能封装到一个js文件中。

其中QQ音乐的关于播放的功能都封装到了player.js的文件中,进度条的功能都封装到了progress.js中,关于歌词的显示部分封装到了lyric.js 中,其他逻辑部分封装到index.js中。

1、index.js

$(function () {
    // 0.自定义滚动条
    $(".content-list").mCustomScrollbar();

    var $audio = $("audio");
    var player = new Player($audio);
    var progress, voiceProgress
    var lyric

    //加载歌曲列表
    getPlayerList();
    function getPlayerList() {
        // 解析json文件
        $.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)
            }

        })
    }

    //初始化歌曲信息
    function initMusicInfo(music) {
        // 获取元素
        var $musicImage = $('.song-info-pic img')
        var $musicName = $('.song-info-name a')
        var $musicSinger = $('.song-info-singer a')
        var $musicAlbum = $('.song-info-album 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)
        $musicAlbum.text(music.album)
        $musicProgressName.text(music.name + ' / ' + music.singer)
        $musicProgressTime.text('00:00 / ' + music.time)
        $musicBg.css("background","url('"+music.cover+"')")
    }

    //初始化歌词信息
    function initMusicLyric(music) {
        lyric = new Lyric(music.link_lrc)
        var $lyricContainer = $('.song-lyric')
        // 清空上一首音乐歌词
        $lyricContainer.html('')
        lyric.loadLyric(function () {
            // 创建歌词列表
            $.each(lyric.lyrics, function (index,ele) {
                var $item = $("<li>" + ele + "</li>")
                $lyricContainer.append($item)
            })
        })
    }

    //初始化进度条
    initProgress()
    function initProgress() {
        var $progressBar = $(".music-progress-bar")
        var $progressLine = $(".music-progress-line")
        var $progressDot = $(".music-progress-dot")
        progress = Progress($progressBar, $progressLine, $progressDot)

        progress.progressClick(function (value) {
            player.musicSeekTo(value)
        })
        progress.progressMove(function (value) {
            player.musicSeekTo(value)
        })


        var $voiceBar = $(".music-voice-bar")
        var $voiceLine = $(".music-voice-line")
        var $voiceDot = $(".music-voice-dot")
        voiceProgress = Progress($voiceBar, $voiceLine, $voiceDot)

        voiceProgress.progressClick(function (value) {
            player.musicVoiceSeekTo(value)
        })
        voiceProgress.progressMove(function (value) {
            player.musicVoiceSeekTo(value)
        })
    }

    //初始化事件监听
    initEvents()
    function initEvents() {
        // 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 () {
            var $item = $(this).parents(".list-music")
            // 3.1切换播放图图标
            $(this).toggleClass("list-menu-play2")
            // 3.2.复原其他的播放图标
            $item.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")
            // 3.5播放音乐
            player.playMusic($item.get(0).index, $item.get(0).music)
            // 3.6切换歌曲信息
            initMusicInfo($item.get(0).music)
            // 3.7切换歌词的信息
            initMusicLyric($item.get(0).music)

        })

        // 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')
        })
        // 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)
            })
        })

        // 8、监听播放的进度
        player.musicTimeUpdate(function (currentTime, duration, timeStr) {
            // 同步时间
            $('.music-progress-time').text(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 +4) * 30) 
            })
            
        })

        // 9、监听声音按钮点击
        $('.music-voice-icon').click(function () {
            // 图表切换
            $(this).toggleClass('music-voice-icon2')
            // 声音切换
            if ($(this).attr('class').indexOf('music-voice-icon2') != -1) {
                // 没有声音
                player.musicVoiceSeekTo(0)
            } else {
                // 有声音
                player.musicVoiceSeekTo(1)
            }
        })

        // 10、监听模式按钮的点击
        $('.music-mode').click(function () {
            // 模式切换
            $(this).toggleClass('music-mode2')
            $(this).toggleClass('music-mode3')
            // $(this).toggleClass('music-mode4')

        })

        // 11、监听纯净模式的点击
        $('.music-only').click(function () {
            // 按钮切换
            $(this).toggleClass('music-only2')
            
        })

    }

    // 定义一个方法创建一条音乐
    function crateMusicItem(index, music) {
        var $item = $("" +
            "<li class=\"list-music\">\n" +
            "<div class=\"list-check\"><i></i></div>\n" +
            "<div class=\"list-number\">" + (index + 1) + "</div>\n" +
            "<div class=\"list-name\">" + music.name + "" +
            "     <div class=\"list-menu\">\n" +
            "          <a href=\"javascript:;\" title=\"播放\" class='list-menu-play'></a>\n" +
            "          <a href=\"javascript:;\" title=\"添加\"></a>\n" +
            "          <a href=\"javascript:;\" title=\"下载\"></a>\n" +
            "          <a href=\"javascript:;\" title=\"分享\"></a>\n" +
            "     </div>\n" +
            "</div>\n" +
            "<div class=\"list-singer\">" + music.singer + "</div>\n" +
            "<div class=\"list-time\">\n" +
            "     <span>" + music.time + "</span>\n" +
            "     <a href=\"javascript:;\" title=\"删除\" class='list-menu-del'></a>\n" +
            "</div>\n" +
            "</li>");
        $item.get(0).index = index
        $item.get(0).music = music
        return $item
    }

})

2、player.js

(function (window) {
    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;
            }
        },
        // 处理播放索引为负数的情况
        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;
        },
        changeMusic: function (index) {
            // 删除对应的数据
            this.musicList.splice(index, 1)
            
            // 判断当前删除的是否是正在播放的音乐的前面的
            if (index < this.currentIndex) {
                this.currentIndex = this.currentIndex -1
            }
        },
        // 封装一个更新音乐时间的方法
        musicTimeUpdate: function (callBack) {
            var $this = this
            this.$audio.on('timeupdate', function () {
                // console.log(player.getMusicDuration(), player.getMusicCurrentTime())
                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
        },
        musicSeekTo: function (value) {
            if (isNaN(value)) return;
            this.audio.currentTime = this.audio.duration * value;
        },
        musicVoiceSeekTo: function (value) {
            if (isNaN(value)) return;
            if (value < 0 || value > 1) return;
            this.audio.volume = value
        }
    }
    Player.prototype.init.prototype = Player.prototype;
    window.Player = Player;
})(window);

3、progress.js

// 操作进度条
(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是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)

                // 计算进度条的比例
                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 () {
                $this.isMove = true
                
                // 2、监听鼠标的拖动事件
                $(document).mousemove(function () {
                    // 获取点击的位置距离窗口的位置
                    eventLeft = event.pageX

                    // 判断进度条的长度是否合法
                    var offset = eventLeft - normalLeft
                    if (offset >= 0 && offset <= barWidth) {
                        // 设置前景的宽度
                        $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)
            })
        },
        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);

4、lyric.js

(function (window) {
    function Lyric(path) {
        return new Lyric.prototype.init(path);
    }
    Lyric.prototype = {
        constructor: Lyric,
        init: function (path) {
            this.path = path
        },
        times :[],
        lyrics: [],
        index : -1,
        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)
                }

            })
        },
        parseLyric: function (data) {
            var $this = this
            // 清空歌词跟时间
            $this.times = []
            $this.lyrics = []
            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)
                // console.log(res)
                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))
                // console.log(typeof time)
                $this.times.push(time)
            })
            // console.log($this.times)
            // console.log($this.lyrics)

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

5、注意点

写jQuery代码你首先导入jQuery库,一个js文件。js文件的导入是有顺序的,在一个js文件中会用到其他的js文件中的方法,导入顺序必须有先后

<link rel="stylesheet" href="css/jquery.mCustomScrollbar.css">
<link rel="stylesheet" href="css/index.css">
<script src="js/jquery-1.12.4.js"></script>
<script src="js/jquery.mCustomScrollbar.concat.min.js"></script>
<script src="js/player.js"></script>
<script src="js/progress.js"></script>
<script src="js/lyric.js"></script>
<script src="js/index.js"></script>
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页
实付 9.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值