微信小程序音频播放之音乐播放器

使用微信小程序实现一个简易的音乐播放器.
Github地址

show.gif

虽然界面很简单,但是一个音频播放器该有的功能大部分都有了(没有歌词显示功能).
主要实现的功能有:
1.实现音频播放,暂停;
2.实现拖拽进度条,快进音频进度;
3.实现上一首,下一首,列表循环播放;
4.实现关闭小程序,也可在后台播放,正式版需要通过审核,开发版本可正常测试;

一丶index.js

  1. 数据初始化
  /**
   * 页面的初始数据
   */
  data: {
    playStatus: true,
    audioIndex: 0,
    progress: 0,
    duration: 0,
    audioList: [],
    showList: true
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function(options) {
    this.setData({
      audioList: data
    })
    this.playMusic();
  },
  1. playMusic 切换播放歌曲的方法.
  playMusic: function() {
    let audio = this.data.audioList[this.data.audioIndex];
    let manager = wx.getBackgroundAudioManager();
    manager.title = audio.name || "音频标题";
    manager.epname = audio.epname || "专辑名称";
    manager.singer = audio.author || "歌手名";
    manager.coverImgUrl = audio.poster;
    // 设置了 src 之后会自动播放
    manager.src = audio.src;
    manager.currentTime = 0;
    let that = this;
    manager.onPlay(function() {
      console.log("======onPlay======");
      that.setData({
        playStatus: true
      })
      that.countTimeDown(that, manager);
    });
    manager.onPause(function() {
      that.setData({
        playStatus: false
      })
      console.log("======onPause======");
    });
    manager.onEnded(function() {
      console.log("======onEnded======");
      that.setData({
        playStatus: false
      })
      setTimeout(function() {
        that.nextMusic();
      }, 1500);
    });
  },
  1. countTimeDown 循环计时,进度展示
  //循环计时
  countTimeDown: function(that, manager, cancel) {
    if (that.data.playStatus) {
      setTimeout(function() {
        if (that.data.playStatus) {
          // console.log("duration: " + manager.duration);
          // console.log(manager.currentTime);
          that.setData({
            progress: Math.ceil(manager.currentTime),
            progressText: that.formatTime(Math.ceil(manager.currentTime)),
            duration: Math.ceil(manager.duration),
            durationText: that.formatTime(Math.ceil(manager.duration))
          })
          that.countTimeDown(that, manager);
        }
      }, 1000)
    }
  },
  1. sliderChange slider的拖拽事件
  //拖动事件
  sliderChange: function(e) {
    let manager = wx.getBackgroundAudioManager();
    manager.pause();
    manager.seek(e.detail.value);
    this.setData({
      progressText: this.formatTime(e.detail.value)
    })
    setTimeout(function() {
      manager.play();
    }, 1000);
  },
  1. lastMusic 上一首
  //上一首
  lastMusic: function() {
    let audioIndex = this.data.audioIndex > 0 ? this.data.audioIndex - 1 : this.data.audioList.length - 1;
    this.setData({
      audioIndex: audioIndex,
      playStatus: false,
      progress: 0,
      progressText: "00:00",
      durationText: "00:00"
    })
    setTimeout(function() {
      this.playMusic();
    }.bind(this), 1000);
  },
  1. playOrpause 中间的按钮,播放/暂停切换
  //播放按钮
  playOrpause: function() {
    let manager = wx.getBackgroundAudioManager();
    if (this.data.playStatus) {
      manager.pause();
    } else {
      manager.play();
    }
  },
  1. nextMusic 下一首
  //下一首
  nextMusic: function() {
    let audioIndex = this.data.audioIndex < this.data.audioList.length - 1 ? this.data.audioIndex + 1 : 0;
    this.setData({
      audioIndex: audioIndex,
      playStatus: false,
      progress: 0,
      progressText: "00:00",
      durationText: "00:00"
    })
    setTimeout(function() {
      this.playMusic();
    }.bind(this), 1000);
  },
  1. listClick 列表点击事件
  //列表点击事件
  listClick: function(e) {
    let pos = e.currentTarget.dataset.pos;
    if (pos != this.data.audioIndex) {
      this.setData({
        audioIndex: pos,
        showList: false
      })
      this.playMusic();
    } else {
      this.setData({
        showList: false
      })
    }
  },
  1. 界面切换,时长格式化
  //界面切换
  pageChange: function() {
    this.setData({
      showList: true
    })
  },

  //格式化时长
  formatTime: function(s) {
    let t = '';
    s = Math.floor(s);
    if (s > -1) {
      let min = Math.floor(s / 60) % 60;
      let sec = s % 60;
      if (min < 10) {
        t += "0";
      }
      t += min + ":";
      if (sec < 10) {
        t += "0";
      }
      t += sec;
    }
    return t;
  },

二丶index.wxml

<!--index.wxml-->
<view class="container">
  <view wx:if="{{showList}}" class="list">
    <view wx:for="{{audioList}}" class='item {{audioIndex==index?"active":""}}' bindtap='listClick' data-pos='{{index}}'>
      <view>{{item.name}}</view>
      <text>{{item.author}}</text>
    </view>
  </view>

  <view wx:else class='background'>
    <view class='info'>
      <view>{{audioList[audioIndex].name||""}}</view>
      <view>{{audioList[audioIndex].author||""}}</view>
    </view>
    <image class='list' bindtap='pageChange' src='/images/list.png'></image>
    <image class='poster {{playStatus?"rotate":"rotate-paused"}}' mode="scaleToFill" src='{{audioList[audioIndex].poster}}'></image>
    <view class='progress'>
      <text>{{progressText}}</text>
      <slider class='bar' bindchange="sliderChange" bindchanging="sliderChanging" value="{{progress}}" step="1" min='0' max='{{duration}}' activeColor="#1aad19" block-size="12" block-color="#1aad19" />
      <text>{{durationText}}</text>
    </view>
    <view class='buttons'>
      <image class='button' bindtap='lastMusic' src='/images/last.png'></image>
      <image class='button' bindtap='playOrpause' src='{{playStatus?"/images/pause.png":"/images/play.png"}}'></image>
      <image class='button' bindtap='nextMusic' src='/images/next.png'></image>
    </view>
  </view>
</view>

三丶index.wxss

/**index.wxss**/

.item {
  border: 1rpx solid #eee;
  padding: 10rpx;
  font-size: 11pt;
}

.active {
  background: #a51515;
  color: #fff;
}

.background {
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  text-align: center;
  background: #f5f5f5;
}

.background .info{
  position: fixed;
  top: 140rpx;
  left: 0;
  right: 0;
  font-size: 12pt;
  color: #353535;
}

.background .list {
  position: fixed;
  right: 40rpx;
  top: 40rpx;
  width: 60rpx;
  height: 60rpx;
}

.background .poster {
  width: 150rpx;
  height: 150rpx;
  border-radius: 50%;
  margin-top: 400rpx;
}

.rotate {
  animation: rotate 10s linear infinite;
}

.rotate-paused {
  animation: rotate 10s linear infinite;
  animation-play-state: paused;
}

@keyframes rotate {
  0% {
    transform: rotate(0deg);
  }

  50% {
    transform: rotate(180deg);
  }

  100% {
    transform: rotate(360deg);
  }
}

.progress {
  position: fixed;
  bottom: 90rpx;
  left: 50rpx;
  right: 50rpx;
  display: flex;
  align-items: center;
  font-size: 10pt;
  color: rgb(87, 49, 49);
  text-align: center;
}

.progress .bar {
  flex: 1;
}

.progress text {
  flex-basis: 90rpx;
}

.buttons {
  position: fixed;
  bottom: 20rpx;
  left: 50rpx;
  right: 50rpx;
  display: flex;
  justify-content: space-around;
  align-items: center;
}

.buttons .button {
  width: 70rpx;
  height: 70rpx;
}

四丶要实现关闭小程序后,依然后台播放,微信顶部悬浮展示,需要再app.json配置requiredBackgroundModes属性


requiredBackgroundModes.png

附上官方相关api链接:
BackgroundAudioManager.html
wx.getBackgroundAudioManager()
slider组件

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

推荐阅读更多精彩内容