zoukankan      html  css  js  c++  java
  • 微信小程序音乐播放器

    写在前面

      1.入门几天小白的作品,希望为您有帮助,有好的意见或简易烦请赐教

      2.微信小程序审核音乐类别已经下架,想要发布选题需慎重。附一个参考链接,感谢https://www.hishop.com.cn/xiaocx/show_53774.html

      3.写的过程中参考了前辈们的方法,借过几位博客园、CSDN、简书前辈的路,这里表示感谢。

      4.官方API很重要

    写在第二

      资深大牛在地铁上问我有没有玩过微信小程序,自觉惭愧。于是萌发了写个小程序长长见识的想法,毕竟,谁都想要做一位行业大牛嘛。

    写这个小程序花了4天,中间第一天无从下手,第二天开悟,到后两天的优化。这中间我收获极大,感谢生活。OK,废话不多说。进入正文

    正文在这里

      先看效果吧 求求你点开我吧

      小程序有两个页面,主页与播放页,因为采用了leanCloud作为后台数据开发,所以有一个lib包

      树结构,上图 附微信小程序使用leanCloud链接

      index页的功能描述:提供音乐查找与选择,搜索框不输入点击搜索得到数据库中所以音乐文件(.mp3格式),支持对歌名或歌手的模糊查询;

    点击列表中的某一首即可跳转至播放页进行播放,从播放页清单回退至index页时,index页底部有播放小窗,点击可回到播放页

      看这里:

      

      代码送上:index.wxml

    <view class='theMain' style='background-image:url({{bgimage}});'>
    <view>
      <image class='image1'src="{{imageUrl}}" mode='aspectFit' wx:if="{{!searchTop}}">
      </image>
    </view>
    <view class='page_row'>  
          <view class="search">  
            <view class="df search_arr">  
              <icon class="searchcion" size='20' type='search'></icon>  
              <input class="searchInput" placeholder="请输入歌名,歌手" value="{{searchValue}}" bindinput='searchValueInput'/>  
            </view>  
          </view>  
          <view class='sousuo' bindtap='sousuoButton'>搜索</view>  
    </view> 
    <view class='listBar'>
      <text class="search_top" style='80%;' wx:if="{{searchTop}}">搜索结果</text>
    </view>
    <view wx:for='{{json}}' class='music_list' bindtap='playTheMusic'data-name="{{item.name}}" data-url="{{item.url}}">
      <text class='musictext'>{{item.name}}</text>
      <view class='url'>{{item.url}}</view>
    </view>
    
    <view class="search_no" wx:if="{{!centent_Show}}">
      <text>暂时没有库存,联系冯大神上传哈</text>
    </view>
    <view class='littlebar' bindtap='littlebar'>
      <view class='littleImage' style='background-image:url({{imageUrl}});'></view>
      <view class='littleName'>
      <text class='songNameText'>{{songName}}</text>
      </view>
    </view>
    </view>

      index.wxss这个css样式代码我觉得就没啥可看的啦,这个还是看自己喜好调,如果需要的话,文章最下方附有Github链接,

    重要的还是在index.js上啦,一起来看看(我觉得不错的地方直接在代码上标注了,可以参考一下)

    const AV = require("../../libs/av-weapp-min");//这里是对LeanCloud的引用,大家需要的话可问度娘,很多详细教程,我还是蛮喜欢这个工具的
    var app=getApp()
    Page({
    
    
      /**
       * 页面的初始数据
       */
      data: {
        imageUrl: "http://lc-9qxpppvr.cn-n1.lcfile.com/9c1af72ea0506789a9b9.jpg",
        searchValue:'',      //搜索值
        centent_Show: true,    //这个可看wxml中的wx:if属性,用来动态显示与隐藏
        searchTop:false,       //同上
        bgimage: '',           //背景图片,在得到搜索结果的时候显示
        toName:'',
        songName:''
      },
    
      searchValueInput: function (e) {//得到搜索框的内容并渲染到data下的searchValue中
        var value = e.detail.value;
        this.setData({
          searchValue: value,
        });
      },
    
      sousuoButton:function(){//对LeanCloud数据库的查询操作
    var that=this; //这里非常重要,注意,此函数中then方法内还有一个函数,而该函数需要用到setData渲染数据。经过两层不可以直接用this.setData var nameQuery1 = new AV.Query('_File'); nameQuery1.contains('name', that.data.searchValue); var nameQuery2 = new AV.Query('_File'); nameQuery2.contains('name', '.mp3'); var query = new AV.Query.and(nameQuery1, nameQuery2);//这里相当于数据库where语句下的and操作 query.find().then(function (results) { // results is an array of AV.Object. //将data转成json格式 //转为数组 var jsonObj = JSON.parse(JSON.stringify(results)); app.globalData.musicList=jsonObj.concat(); //设置了全局变量,concat()方法为数组的复制,playing页面需要。具体用法可问度娘,app对象为顶部创建的对象 if (jsonObj.length == 0) { that.setData({ centent_Show: false, }); return; } that.setData({ json: app.globalData.musicList, searchTop:true, bgimage: "http://lc-9qxpppvr.cn-n1.lcfile.com/9c1af72ea0506789a9b9.jpg", centent_Show:true }); console.log(that.data.c) }, function (error) { console.log(error); // error is an instance of AVError. }); }, //点击底部音乐bar进入play界面 littlebar: function () { //这里有一个较难解决的问题,我会在下面单独写出,大神要是有思路请赐教,毕竟我才入门4天,很多都不懂 var pages=getCurrentPages(); var playingPage=pages[pages.length-2]; playingPage.setData({ angle:app.globalData.angle, }) wx.navigateBack(); }, //点击清单跳转到播放界面
      //data-name="{{item.name}}" data-url="{{item.url}}"
    //只有在列表渲染的view控件中设置这些属性,该函数才可得到点击后对应的属性(可见上面的index.wxml)

    playTheMusic:function(e){
        console.log(e.currentTarget.dataset.name);  //一个调试方法,调试器输出点击的歌曲名
        this.setData({
          toName: e.currentTarget.dataset.name
        });
        var songUrl = e.currentTarget.dataset.url;
        var songName = e.currentTarget.dataset.name;
        app.globalData.songName = songName;
        var theUrl = "../playing/playing?songUrl=" + songUrl + "&songName=" + songName //url携带参数
        wx.redirectTo({  //此种跳转当前页面数据会保存在页面栈中,可以回退,可问度娘      
        url: theUrl,
      })
      },
    
      /**
       * 生命周期函数--监听页面加载
       */
      onLoad: function (options) {
        /** 
         * 监听音乐播放 
         */
        wx.onBackgroundAudioPlay(function () {
          // callback
          console.log('onBackgroundAudioPlay')
        })
      },
    /**
       * 生命周期函数--监听页面显示
       */
      onShow: functionthis.setData({
          songName: app.globalData.songName ,
          json: app.globalData.musicList,
          searchTop: true,
        }); 
      }
    })

      好了,这里我想谈一下在index.js中我提到的单独讲的内容。情景在于微信小程序界面之间的跳转,使用wx.navigateTo()方法跳转到另一个页面时可以将当前页面存入页面栈,再通过wx.navigateBack()方法对页面栈出栈操作,可回退到当前页面,使用wx.redirectTo()直接跳转,不存入页面栈。在这个程序中,index->playing->index->playing重复多次无法直接实现。这个问题我想了很久还是没有完美的将其解决。

      我的暂时逻辑是:点击对应音乐使用wx.redirectTo()方法,不保存页面栈,跳转至playing页;在playing页点击list图标使用wx.navigateTo(),保存页面栈,同时跳到index页,这时候会调用onShow()函数,将保存的list信息渲染到index页面上;点击index底部的播放小框调用wx.navigateBack()方法回到playing页(playing页的数据较多,所以采用了这种逻辑)

      哪位大哥有更好解决方法烦请赐教哈

      接下来是playing页:(推荐使用wx.getBackgroundAudioManager()接口对音乐行为进行操作

      此页面需要完成播放、暂停、上一曲、下一曲、回到index页、动态显示播放时间和总长度(部分实现)、快进(还未实现)

      看界面:

      

      然后上代码了:
      playing.wxml:图标来源于百度图片,简单ps抠图后传至云端使用;中间专辑图旋转感谢这篇博客,其中的旋转快慢,每次角度可通过调节常量值实现,下面代码有标注

    <view class='Main'>
      <view class='songNameView'>
        <text></text>
        <text class='songName'>{{name}}</text>
      </view>
      <view class='imageView' style="background-image: url({{imageUrl}});" animation="{{animationData}}">
      </view>
       <view class="backIndex" bindtap='backIndex' style='background-image:url({{homeImage}})'></view>
      <view class='line'>
        <view class='nowView'>
          <text class='now'>{{cur}}</text>
        </view>
        <view class='theLine'></view>
        <view class='allTimeView'>
          <text class='allTime'>{{duration}}</text>
        </view>
      </view>
      <view class="button">
        <view class='back MusicIcon' style="background-image: url({{backUrl}});" bindtap='theBack'></view>
        <view class='center MusicIcon' style="background-image: url({{playOrStopUrl}});" bindtap='play'></view>
        <view class='next MusicIcon' style="background-image: url({{nextUrl}});" bindtap='theNext'></view>
      </view>
    </view>

    同样,playing.wxss可在我的Github中查看

    下面是展示playing.js的时刻,各种逻辑在代码中直接标注了

    // pages/playing/playing.js
    const AV = require("../../libs/av-weapp-min");
    var app = getApp()
    Page({
    
      /**
       * 页面的初始数据
       */
      data: {
        name:'测试',
        url:'',
        imageUrl:'http://lc-9qxpppvr.cn-n1.lcfile.com/9c1af72ea0506789a9b9.jpg',
        homeImage:"http://lc-9qxpppvr.cn-n1.lcfile.com/a9603240aab63a7950b0.png",
        animationData: {},
        isPlay:false,   //播放标志
        thePosition:0,  //用来保存暂停时播放位置
        angle:0,        //用来不断保存旋转次数,用于解决界面多次跳转后旋转失速问题
        cur:'--:--',    //当前时间
        duration:'--:--'  //总时长
      
      },
      //返回到清单页

    //此处在上面有提及,点击list图标到index页面,并将跳转前最后一个旋转角度渲染给全局变量 backIndex: function () { wx.navigateTo({ url: '../index/index', }); app.globalData.angle=this.data.angle; }, /** * 生命周期函数--监听页面加载 */ onLoad: function (options) { //加载传递过来的参数
      //options为随url传递过来的参数
    this.setData({ name: options.songName, url: options.songUrl, imageUrl:"http://lc-9qxpppvr.cn-n1.lcfile.com/9c1af72ea0506789a9b9.jpg", backUrl:"http://lc-9qxpppvr.cn-n1.lcfile.com/2574f1888750f8eaea88.png", nextUrl:"http://lc-9qxpppvr.cn-n1.lcfile.com/299a6353324cb312b00e.png", playOrStopUrl:"http://lc-9qxpppvr.cn-n1.lcfile.com/56885a2b7b3e478dd0c6.png", isPlay:true }) //加载页面时执行播放动作 wx.playBackgroundAudio({ dataUrl: this.data.url, }) }, //播放/暂停 play:function(){ const backgroundAudioManager = wx.getBackgroundAudioManager(); var theTime; var allTime; if(this.data.isPlay){ wx.pauseBackgroundAudio(); //推荐都使用这个API,我之前不知道这个API,导致在后来的开发中无法实现上面列举的全部功能 theTime = backgroundAudioManager.currentTime;//不甘心,所以在点击播放或暂停时可对页面进行时间的动态渲染,也算是完成了一点吧 allTime = backgroundAudioManager.duration; var theString1 = theTime.toFixed(0); var theInt1 = parseInt(theString1); var m1 = theInt1 / 60; var mString1 = m1.toFixed(0); //截取小数点后0位数字,结果为String类型 var mInt1 = parseInt(mString1); //转number var s1 = theInt1 % 60 / 100; var cur = mInt1 + s1; var theString = allTime.toFixed(0); var theInt = parseInt(theString); var m = theInt/60; var mString = m.toFixed(0); var mInt = parseInt(mString); var s = theInt%60/100; var all = mInt+s; this.setData({ playOrStopUrl:"http://lc-9qxpppvr.cn-n1.lcfile.com/22a26757fca8c46a2940.png",//替换为暂停图标 isPlay: false, //渲染一些需要的数据 thePosition: theTime, duration:all, cur: cur }); }else{ backgroundAudioManager.seek(this.data.thePosition); backgroundAudioManager.play(); this.setData({ playOrStopUrl: "http://lc-9qxpppvr.cn-n1.lcfile.com/56885a2b7b3e478dd0c6.png", isPlay:true }); } }, //下一首 theNext:function(){//对全局变量下的查找清单进行操作,如果当前歌曲为最后一首,跳转到第一首 var j; var musicList = getApp().globalData.musicList.concat(); for (var i = 0; i < musicList.length;i++){ if(musicList[i].name==this.data.name){ j=i; break; }else{ j=-1; } } if (musicList.length-1==j){ this.setData({ name: musicList[0].name, url: musicList[0].url }); }else{ this.setData({ name: musicList[j+1].name, url: musicList[j + 1].url }); } wx.playBackgroundAudio({ dataUrl: this.data.url, }) }, //上一首 theBack:function(){//若为第一首,跳转到最后一首 var j; var theLength=0; var musicList = getApp().globalData.musicList.concat(); theLength=musicList.length; for (var i = 0; i < musicList.length; i++) { if (musicList[i].name == this.data.name) { j = i; break; } else { j = 1; } } if (j==0) { this.setData({ name: musicList[theLength-1].name, url: musicList[theLength-1].url }); } else { this.setData({ name: musicList[j-1].name, url: musicList[j-1].url }); } wx.playBackgroundAudio({ dataUrl: this.data.url, }) },/** * 生命周期函数--监听页面显示 */ onShow: function () {//这里为专辑图旋转函数,调用wx.createAnimation()接口,更多参数详情可看官方API var animation = wx.createAnimation({ duration: 1000, timingFunction: 'ease', }) this.animation = animation // animation.scale(2, 2).rotate(45).step() this.setData({ animationData: animation.export() }) var n = 0; //连续动画需要添加定时器,所传参数每次+1就行 setInterval(function () { n=this.data.angle; if(this.data.isPlay){//暂停时停止旋转,播放旋转的逻辑 n = n + 1; }else{ n=n; } this.setData({ angle: n, }) this.animation.rotate(8 * n).step()//8为每次转8°,应该是,个人喜好设置 this.setData({ animationData: this.animation.export() }) }.bind(this), 360)//360ms转一个角度,个人喜好设置 } })

      OK,到这里就可以实现一个演示视频中所有功能的简易播放器了,是不是觉得很简单。

      相对于网上很多前辈的功能完善的音乐播放器来说,我这个真的是望尘莫及,未来还有很长的路要走。但是东西出来了嘛, 还是很开心的;当然,我还是会不断的去完善它的,这之中的playing页面的专辑图浮动旋转效果是我最惊喜的了,之前只是想加个阴影,没想到阴影可以跟随旋转,贼帅。

      感谢可爱的你看了这篇博客

      附Github:https://github.com/fengjirong/musicByfeng

  • 相关阅读:
    原码, 反码, 补码 详解
    二进制与十进制间的转换方法(图文教程)
    题目要求:将a,b两个数的值进行交换,并且不使用任何的中间变量。
    【转】面向对象的7个基本设计原则
    【转】UML类图符号 6种关系说明以及举例
    关于try catch
    关于异常
    java File类中的mkdir()和mkdirs()有什么区别
    反射中getMethods 与 getDeclaredMethods 的区别
    【转】Java利用反射机制访问私有化构造器
  • 原文地址:https://www.cnblogs.com/fjrgg/p/9540919.html
Copyright © 2011-2022 走看看