在线音乐播放器搭建

一、所涉及到的相关知识应用:

1.ajax 的使用;
2.DOM 的操作;
3.关于事件相关的一些操作;
4.音乐相关 api 的使用。

二、整理核心点逻辑,并对功能有一定认识:

1. 音乐从哪里来:

比如说歌曲的数据可以放在一个数组里面,直接去用;也可以通过从服务端去获取,使用 ajax 去获取数据。
获取到之后就得到一个音乐的数据,一个数组。我们得到的音乐数据应该包括:音乐标题、作者、背景图片、音乐地址。

2. 如何去操作播放音乐:

比如我有了一个音乐地址,应该如何去播放?音量我能不能控制?播放过程中播放了多少时间我能不能得到,能不能去暂停它?
这些即我们需要的功能,或者说技术关键点。

3. 如何把他们组装起来。

比如把音乐播放器放在页面上,然后结合事件,当点击按钮时再执行对应具体操作。

三、. 音乐播放器

1. API

1. audioObject

创建或者获取的 audio 对象,可通过以下两种方式得到:

方法一:

<audio id="music" src="http://cloud.hunger-valley.com/music/玫瑰.mp3">你的浏览器不支持喔!</audio>
<script>
var audioObject = document.querySelector('#music')
</script>

方法二:

var audioObject = new Audio('http://cloud.hunger-valley.com/music/玫瑰.mp3')
2. audioObject.play()

开始播放

3. audioObject.pause()

暂停播放

4. audioObject.autoplay()

设置或者获取自动播放状态:

audioObject.autoPlay = true  //设置为自动播放,下次更换 audioObject.src 后会自动播放音乐
audioObject.autoPlay = false //设置不自动播放
console.log(audioObject.autoPlay)
5. audioObject.src

设置或者获取音乐地址:

audioObject.src = "http://cloud.hunger-valley.com/music/ifyou.mp3"
console.log(audioObject.src)
6. audioObject.volume

设置或者获取音量,最大值为 1,0 为静音:

audioObject.volume = 0.5
audioObject.volume = 1
console.log(audioObject.volume)
7. audioObject.loop

设置或者获取循环状态:

audioObject.loop = true
console.log(audioObject.loop)
8. audioObject.duration

获取音乐长度,单位为秒:

console.log(audioObject.duration)
9. audioObject.currentTime

设置或者获取播放时间:

console.log(audioObject.currentTime)
10. audioObject.ended

判断音乐是否播放完毕,只读属性。

2. 事件

1. playing

当音乐开始播放,暂停后重新开始播放,设置 currenTime 后开始播放时触发:

audioObject.addEventListener('playing', function(){
  console.log('playing')
})
2. pause

当音乐暂停时和结束时触发:

audioObject.addEventListener('pause', function(){
console.log('pause')
})
3. ended

当音乐结束时触发:

audioObject.addEventListener('ended', function(){
  console.log('ended')
})
4. timeupdate

当 currentTime 更新时会触发 timeupdate 事件,这个事件的触发频率由系统决定,但是会保证每秒触发 4-66 次(前提是每次事件处理不会超过250ms):

//如下代码设置 每1秒左右执行一次
audioObject.shouldUpdate = true
audioObject.ontimeupdate = function(){
  var _this = this
  if(_this.shouldUpdate) {
     //do something
     console.log('update')
     _this.shouldUpdate = false
    setTimeout(function(){
      _this.shouldUpdate = true
    }, 1000)
  }
}
5. volumechange

当音量改变时触发:

audioObject.onvolumechange = function(){
 console.log('volumechage')
})

整合后的代码:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>音乐播放器</title>
    <link rel="stylesheet" href="http://at.alicdn.com/t/font_881589_c0dwmabq02l.css">
    <style>
      /* reset.css */
      * {
        margin: 0;
        padding: 0;
      }


      /* common.css */
      body {
        height: 100vh;
      }

      .cover {
        position: absolute;
        content: '';
        display: block;
        width: 100%;
        height: 100%;
        background: url(http://cloud.hunger-valley.com/17-9-22/87786461.jpg) center center no-repeat;
        background-size: cover;
        filter: blur(3px);
      }

      /* index.css */
      .musicbox {
        position: absolute;
        left: 50%;
        top: 40%;
        transform: translate(-50%, -50%);
        font-family: cursive;
        font-size: 16px;
        color: #f06d6a;
        width: 340px;
      }

      .music-panel {
        border: 1px solid #76dba3;
        padding: 20px 20px 5px 20px;
        box-shadow: 0px 2px 5px 0px rgba(0,0,0,.1), 0px 2px 10px 0px rgba(0,0,0,.05);
        background-color: rgba(255,255,255,.9);
      }

      .musicbox .control {
        margin-top: 20px;
        font-size: 22px;
        color: #ee8a87;
        float: left;
      }

      .musicbox .control .iconfont {
        margin-right: 12px;
        cursor: pointer;
      }

      .musicbox .control .iconfont.disable {
        opacity: 0.3;
      }

      .musicbox .info {
        margin-left: 120px;
      }

      .musicbox .info .title {
        font-size: 18px;
      }

      .musicbox .info .author {
        font-size: 13px;
      }

      .musicbox .progress {
        width: 260px;
      }

      .musicbox .progress .bar {
        height: 3px;
        margin-top: 5px;
        background-color: rgba(0,0,0,.2);
        cursor: pointer;
      }

      .musicbox .progress .progress-now {
        height: 2px;
        width: 0;
        background-color: #ee8a87;
        position: relative;
      }

      .musicbox .time {
        text-align: right;
      }

      .musicbox:after,
      .musicbox .music:after {
        content: '';
        display: block;
        clear: both;
      }

      .musicbox .list {
        list-style: none;
      }

      .musicbox .list>li {
        position: relative;
        padding: 4px 10px;
        border: 1px solid rgba(255,255,255,.8);
        border-top: none;
        overflow: hidden;
        cursor: pointer;
        background-color: rgba(0,0,0,.8);
      }

      .musicbox .list>li:hover {
        background-color: rgba(255,255,255,.5);
      }

      .musicbox .list>li.playing:before {
        position: absolute;
        top: 0;
        left: 0;
        content: '';
        display: inline-block;
        width: 8px;
        height: 30px;
        background: rgba(255,255,255,.8);
      }

    </style>
  </head>
  <body>
    <!-- index.html -->
    <div class="cover"></div>
    <div class="musicbox">
      <div class="music-panel">
        <div class="music">
          <div class="control">
            <span class="back"><i class=" iconfont icon-back"></i></span>
            <span class="play"><i class=" iconfont icon-play"></i></span>
            <span class="forward"><i class=" iconfont icon-forward"></i></span>
          </div>
          <div class="info">
            <div class="title">My Song</div>
            <div class="author">Jay</div>
          </div>
        </div>
        <div class="progress">
          <div class="bar">
            <div class="progress-total"></div>
            <div class="progress-now"></div>
          </div>
          <div class="time">0:00</div>
        </div>
        <ul class="list">
          <li>贰佰-玫瑰</li>
          <li>IF YOU-Big Bang</li>
        </ul>
      </div>
    </div>


    <script>
      // index.js

      // function $(selector){
      //   return document.querySelector(selector);
      // }


      // var musicList = [];
      // var currentIndex = 0;
      // var clock;
      // var audio = new Audio();
      // audio.autoplay = true;

      // getMusicList(function(list){
      //   musicList = list;
      //   loadMusic(list[currentIndex]);
      //   generateList(list);
      // });

      // audio.ontimeupdate = function(){
      //   $('.musicbox .progress-now').style.width = (this.currentTime/this.duration)*100 + '%';
      // };

      // audio.onplay = function(){
      //   clock =setInterval(function(){
      //     var min = Math.floor(audio.currentTime/60);
      //     var sec = Math.floor(audio.currentTime%60) + '';
      //     sec = sec.length ===2? sec : '0' + sec;
      //     $('.musicbox .time').innerText = min + ':' +sec;
      //   }, 1000);
      // };

      // audio.onpause = function(){
      //   clearInterval(clock);
      // };

      // audio.onended = function(){
      //   concole.log('end');
      //   currentIndex = (++currentIndex)%musicList.length;
      //   loadMusic(musicList[currentIndex]);
      // };

      // $('.musicbox .play').onclick = function(){
      //   if(audio.paused){
      //     audio.play();
      //     this.querySelector('.iconfont').classList.remove('icon-play');
      //     this.querySelector('.iconfont').classList.add('icon-pause');
      //   }else {
      //     audio.pause();
      //     this.querySelector('.iconfont').classList.add('icon-play');
      //     this.querySelector('.iconfont').classList.remove('icon-pause');
      //   }
      // };

      // $('.musicbox .forward').onclick = function(){
      //   currentIndex = (++currentIndex)%musicList.length;
      //   loadMusic(musicList[currentIndex]);
      // };

      // $('.musicbox .back').onclick = function(){
      //   currentIndex = (musicList.length + --currentIndex)%musicList.length;
      //   loadMusic(musicList[currentIndex]);
      // };

      // $('.music .bar').onclik = function(e){
      //   console.log(e);
      //   var percent = e.offsetX / parseInt(getComputedStyle(this).width);
      //   console.log(percent);
      //   audio.currentTime = audio.duration * percent;
      // };

      // function getMusicList(callback){
      //   var xhr = new XMLHttpRequest();
      //   xhr.open('Get', '/music.json', true);
      //   xhr.onload = function(){
      //     if((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304){
      //       callback(JSON.parse(this.responseText));
      //     }else {
      //       console.log('获取数据失败');
      //     }
      //   };
      //   xhr.onerror = function(){
      //     console.log('网络异常');
      //   };
      //   xhr.send();
      // }

      // function loadMusic(musicObj){
      //   console.log('begin play', musicObj);
      //   $('.musicbox .title').innerText = musicObj.title;
      //   $('.musicbox .author').innerText = musicObj.author;
      //   $('.cover').style.backgroundImage = 'url(' + musciObj.img + ')';
      //   audio.src = musicObj.src;
      // }


      var musicList = [
        {
          src: 'http://cloud.hunger-valley.com/music/玫瑰.mp3',
          title: '玫瑰',
          author: '贰佰',
          img: 'https://upload-images.jianshu.io/upload_images/3624093-d9678a0d2a897390.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240'
        },
        {
          src: 'http://cloud.hunger-valley.com/music/ifyou.mp3',
          title: 'IF YOU',
          author: 'Big Bang',
          img: 'https://upload-images.jianshu.io/upload_images/3624093-84598b108b24d414.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240'
        }

      ];


      var cover = document.querySelector('.cover');
      var backBtn = document.querySelector('.musicbox .back');
      var playBtn = document.querySelector('.musicbox .play');
      var forwardBtn = document.querySelector('.musicbox .forward');
      var titleNode = document.querySelector('.musicbox .title');
      var authorNode = document.querySelector('.musicbox .author');
      var timeNode = document.querySelector('.musicbox .time');
      var progressBarNode = document.querySelector('.musicbox .progress .bar');
      var progressNowNode = document.querySelector('.musicbox .progress-now');
      var musicListContainer = document.querySelector('.musicbox .list');
      var timer;
      var musicList;

      var music = new Audio();
      music.autoplay = true;
      var musicIndex = 0;

      getMusic(function(list){
        musicList = list;
        setPlaylist(list);
        loadMusic(list[musicIndex]);
      });

      playBtn.onclick = function() {
        var icon = this.querySelector('.iconfont');
        if(icon.classList.contains('icon-play')) {
          music.play();
        }else {
          music.pause();
        }
        icon.classList.toggle('icon-play');
        icon.classList.toggle('icon-pause');
      };

      forwardBtn.onclick = loadNextMusic;
      backBtn.onclick = loadLastMusic;
      music.onended = loadNextMusic;
      music.shouldUpdate = true;

      music.onplaying = function() {
        timer = setInterval(function() {
          updateProgress();
        }, 1000);
        console.log('play');
      };

      music.onpause = function() {
        console.log('pause');
        clearInterval(timer);
      };

      music.ontimeupdate = updateProgress;

      progressBarNode.onclick = function(e) {
        var percent = e.offsetX / parseInt(getComputedStyle(this).width);
        music.currentTime = percent * music.duration;
        progressNowNode.style.width = percent *100 + "%";
      };

      musicListContainer.onclick = function(e) {
        if(e.target.tagName.toLowerCase() === 'li'){
          for(var i = 0; i < this.children.length; i++){
            if(this.children[i] === e.target){
              musicIndex = i;
            }
          }
          console.log(musicIndex);
          loadMusic(musicList[musicIndex]);
        }
      };


      function setPlaylist(musiclist) {
        var container = document.createDocumentFragment();
        musiclist.forEach(function(musicObj){
          var node = document.createElement('li');
          node.innerText = musicObj.author + '-' + musicObj.title;
          console.log(node);
          container.appendChild(node);
        });
        musicListContainer.appendChild(container);
      }

      function loadMusic(songObj) {
        music.src = songObj.src;
        titleNode.innerText = songObj.title;
        authorNode.innerText = songObj.author;
        cover.style.backgroundImage = 'url(' + songObj.img + ')';
        for(var i = 0; i < musicListContainer.children.length; i++){
          musicListContainer.children[i].classList.remove('playing');
        }
        musicListContainer.children[musicIndex].classList.add('playing');
      }

      function loadNextMusic() {
        musicIndex++;
        musicIndex = musicIndex % musicList.length;
        loadMusic(musicList[musicIndex]);
      }

      function loadLastMusic() {
        musicIndex--;
        musicIndex = (musicIndex + musicList.length) % musicList.length;
        loadMusic(musicList[musicIndex]);
      }

      function updateProgress() {
        var percent = (music.currentTime / music.duration) * 100 + '%';
        progressNowNode.style.width = percent;
        var minutes = parseInt(music.currentTime / 60);
        var seconds = parseInt(music.currentTime % 60) + '';
        seconds = seconds.length == 2 ? seconds : '0' + seconds;
        timeNode.innerText = minutes + ':' + seconds;
      }

      function getMusic(callback) {
        var xhr = new XMLHttpRequest();
        xhr.open('get', 'music.json', true);
        xhr.send();
        xhr.onload = function() {
          if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
            callback(JSON.parse(xhr.responseText));
          }
        };
      }

    </script>
  </body>
</html>

预览效果

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容