微信PHP开发《音乐播放器》


前言

时隔好几个月终于想起了自己的博客了,哈哈哈,今天给大家分享的是一个我自己的课程实训项目——微信PHP开发《音乐播放器》,顺带给大家也分享一下我自己学习到的知识,话不多说我们开始吧

一、简介

  1. 相信大家都有所了解,学习了这个课程,以后前端的朋友学习Vue框架也会相对来说比较容易,在此之前,我们需要学习一下如何引入库,以及引入库的一些条件,以下链接都是安全可用的官方链接,可以点击跳转,也可以复制,老手可根据目录进行查看,跳过新手教程。
  2. 因为作者并没有自己的API,本案例所需要的API都来自:
    https://blog.csdn.net/weixin_44358443/article/details/114853183
  3. 还有一些按钮的icon自己去阿里巴巴矢量图标库下载吧,链接:
    https://www.iconfont.cn/

二、引入Vant框架

1.引入库

首先你得安装好node.js
如果没有的话,官方链接如下:
https://nodejs.org/en/
在你安装好了node.js的前提下,打开自己的项目根目录
在这里插入图片描述
点击路径,输入cmd
在这里插入图片描述
会弹出以下界面:
在这里插入图片描述
首先需要初始化一下,输入: npm init
输入命令后一路按回车,按到如下所示:
在这里插入图片描述
表示初始化成功了,接下来可以引入vant框架了
官网:https://vant-contrib.gitee.io/vant-weapp/#/home
注:照着官网文档做即可这里不做多介绍
在这里插入图片描述

2.需要用到的知识

  1. 网络请求
//因为函数的指向问题,在下面设置数据到data中需要外界的this指向,先定义好变量
 var that = this
//利用wx.request这个函数发送请求
    wx.request({
    //key=这里不做写死,可以实现动态请求不同的参数
      url: 'http://iecoxe.top:5000/v1/kuwo/search?key=' + this.data.value,
      //使用success函数,附带参数,可以接收返回的值
      success: function (res) {
      //打印一下,可以查看返回的数值
        console.log(res)
      //当返回的状态码==400时,说明该请求是坏的,我们弹出提示
      	if (res.statusCode == 400) {
          wx.showToast({
            title: '这是一个坏的请求,请重新试试吧',
            icon: 'none',
          })
        }
        //将数据设置到data中,这里的that是上面定义的
        that.setData({
          //获取到名字用来渲染在搜索框
          list: res.data.data.list
        })
      }
    })
  1. 列表渲染
    如果不愿意看我的,可以去官方的链接:https://developers.weixin.qq.com/miniprogram/dev/reference/wxml/list.html
    在我看来,无非就是利用数组的长度循环,创建出组件,顺便给组件附带该数组的值,例如:
    js文件:
Page({
  data: {
  //定义一个空的数组来接收网络请求回传的数据
    list:[],
  },
  onLoad: function (options) {
    //因为函数的指向问题,在下面设置数据到data中需要外界的this指向,先定义好变量
 var that = this
 //利用wx.request这个函数发送请求
     wx.request({
     //key=这里不做写死,可以实现动态请求不同的参数
       url: 'http://iecoxe.top:5000/v1/kuwo/search?key=周杰伦',
       //使用success函数,附带参数,可以接收返回的值
       success: function (res) {
       //打印一下,可以查看返回的数值
         console.log(res)
       //当返回的状态码==400时,说明该请求是坏的,我们弹出提示
         if (res.statusCode == 400) {
           wx.showToast({
             title: '这是一个坏的请求,请重新试试吧',
             icon: 'none',
           })
         }
         //将数据设置到data中,这里的that是上面定义的
         that.setData({
           //接收返回的数据中的,data中的data中的list这个数组
           list: res.data.data.list
         })
       }
     })
  },
})

js中网络请求返回的数据:
在这里插入图片描述
在这里插入图片描述

wxml文件

<--! 可以看出这返回的是一个多维数组,从状态码中可以看出200是正常的请求,xml的注释太恶心了,下面我就直接写文字了 -->
<view wx:for="{{list}}">
    <!-- 数组中的歌名 -->
    <view>{{item.album}}</view>
    <image src="{{item.albumpic}}"></image>
</view>

结果:
在这里插入图片描述

  1. 页面跳转和页面数据传输
wxml代码:这里以按钮为例子,data-??中可以在点击时附带一些数据回传js中
 	<button data-id="1" bindtap="testOnClick">
   		跳转测试
 	</button>
js代码:
	testOnClick:function (e) {
	//点击事件附带参数,用e.currentTarget.dataset.??获取到按钮回传的数据,由于我们设置的值是id,这里就写id
    wx.navigateTo({
    //附带一个id,传递到别的页面,值是点击回传的值
      url: '../test/test?id='+e.currentTarget.dataset.id,
    })
  },
	接收页面的js
onLoad: function (options) {
    //我是别的页面传递过来的数据,利用options.id获取
    var id = options.id;
    //设置到data中
    this.setData({
      id:id
    })
},
	接收页面的wxml
<!-- 我是传递过来的数据 -->
<view>我是传递过来的数据:{{id}}</view>

三、页面编写,以及js的实现

1.首页

首页:index.wxml
<!-- 通知条 -->
<van-sticky>
<view>
  <!-- closeable 模式,在右侧显示关闭按钮 -->
<van-notice-bar mode="closeable" text="技术是开发它的人的共同灵魂。" />
</view>
</van-sticky>
 <!-- 搜索栏 -->
 <van-sticky>
 <view class="container-search" bindtap="search">
    <van-search value="" label="" placeholder="阿拉斯加海湾 为你推荐" use-action-slot="true" bind:change="onChange" bind:search="onSearch">
    </van-search>
  </view>
</van-sticky>
 <!-- 三个榜单 官方榜单 特色榜单 场景榜单  -->
 <view wx:for="{{ccc}}">
   <!-- title -->
  <view style="font-size:25px;margin-left:15px;margin-top:5px">
    {{item.name}}
</view>
<view class="b">
 <!-- 纵向滑动块 -->
 <scroll-view class="scroll-view_H" scroll-x="true">
    <view class="scroll-view-item_H" wx:for="{{item.list}}" data-name="{{item.name}}" data-id="{{item.sourceid}}" bindtap="OfficialList">
      <image  src="{{item.pic}}">
      </image>
      <text>
        {{item.name}}
      </text>
    </view>
  </scroll-view>
</view>
 </view>
首页:index.wxss
/* 搜索框 */
.container-search{
  width: 100%;
  
}
/* 滑动块 */
.scroll-view_H{
  margin-left: 25px;
  margin-top: -80px;
  white-space: nowrap;
  width: 100%
}
.scroll-view-item_H{

  display: inline-block;
  width: 300rpx;
  height: 270rpx;
}
.scroll-view-item_H image{
  width: 250rpx;
  height: 200rpx;
  margin-top: 25px;
}
.scroll-view-item_H text{
  margin-left: 25px;
  text-align: right;
  width: 250rpx;
}
.b{
  margin-top: 80px;
  margin-left: -15px;
}
首页:index.js
// 获取应用实例
const app = getApp()

Page({
  data: {
    value: '',
    active: 0,
    percentage:0,
    time: '03:45',
    hours: '0' + 0, // 时
    minute: '0' + 0, // 分
    second: '0' + 0, // 秒
  },
  testOnClick:function (e) {
    wx.navigateTo({
      url: '../test/test?id='+e.currentTarget.dataset.id,
    })
  },
  //点击搜索按钮
  search: function () {
    //点击跳转搜索页面
    wx.navigateTo({
      url: '../search/search'
    })
  },
  //点击跳转
  OfficialList:function (e) {
    var that = this
    console.log(e.currentTarget.dataset.id)
    var name = 
    wx.navigateTo({
      url: '../list/list?id='+e.currentTarget.dataset.id+'&name='+ e.currentTarget.dataset.name,
    })
  },
  aaa:function () {
    var that = this
    wx.request({
      url: 'http://iecoxe.top:5000/v1/kuwo/top?topId=93',
      success:function (res) {
        console.log(res)
        that.setData({

        })
      }
    })
    // console.log(this.data.ccc)
  },
  ccc:function () {
    var that = this
    wx.request({
      url: 'http://iecoxe.top:5000/v1/kuwo/topCategory',
      success:function (res) {
        console.log(res.data.data)
        that.setData({
          ccc:res.data.data
        })
      }
    })
    console.log(this.data.ccc)
  },
  //点击事件
  onChange(event) {
    // event.detail 的值为当前选中项的索引
    this.setData({ active: event.detail });
    if (event.detail == 1) {
      wx.navigateTo({
        url: '../play/play',
      })
    }
  },
  // 搜索按钮点击事件
  onSearch() {
    console.log("搜索按钮点击事件")
  },
  onLoad() {
    this.aaa()
    this.ccc()
    if (wx.getUserProfile) {
      this.setData({
        canIUseGetUserProfile: true
      })
    }
  },
})

在这里插入图片描述

在首页,我获取了api中的热搜榜,利用热搜榜返回的数据来对页面进行渲染,对滑动块进行了规划,也有对应的标题,在囊括滑动块的view中设置对应的点击事件,实现页面的跳转,并附带数据回传,实现数据的跨页面传输,如:歌单的id,等待,在搜索框中,不提供搜索,而是直接进入对应的搜索页进行搜索。

2.搜索页

搜索页:search.wxml
<van-search
  value="{{ value }}"
  label=""
  placeholder="请输入搜索关键词"
  use-action-slot="true"
  bind:change="onChange"
  bind:search="onSearch"
>
  <view slot="action" bind:tap="onClick">搜索</view>
</van-search>
<!-- 热门搜索 -->
<view>热门搜索:</view>
<view class="hotsearch" wx:for="{{list}}">
  <button class="button-hotsearch" data-name="{{item.key}}" bindtap="hotSearchOnClick">{{item.key}}</button>
</view>
搜索页:search.wxss 
/* pages/search/search.wxss */
.hotsearch{
  margin-left: 30px;
  margin-top: 10px;
}
.button-hotsearch{
  margin-bottom: 10px;
  font-size: 12px;
  float: left;
  height: 25px;
  margin-right: 10px;
}
搜索页:search.js
// pages/search/search.js
Page({
  //热门搜索点击事件
  hotSearchOnClick:function (e) {
    var name = e.currentTarget.dataset.name
    //点击跳转并传递数据(歌名)进行搜索
    wx.navigateTo({
      url: '../getSearchMusic/getSearchMusic?name='+ name,
    })
  },
  //输入的内容
  onChange(e) {
    this.setData({
      value: e.detail,
    });
  },
  //点击搜索按钮
  onClick() {
    //打印输入的内容
    console.log(this.data.value)
    var name = this.data.value
    //点击跳转并传递数据(歌名)进行搜索
    wx.navigateTo({
      url: '../getSearchMusic/getSearchMusic?name='+ name,
    })
  },
  /**
   * 页面的初始数据
   */
  data: {
    value:'阿拉斯加海湾',//设置搜索默认值
    list:null,
  },

  /**
   * 生命周期函数--监听页面加载
   */
  //获取热门搜索
  getHotSearch:function () {
    var that = this
    wx.request({
      url: 'http://iecoxe.top:5000/v1/kuwo/hotSearch',
      success: function (res) {
        console.log(res)
        that.setData({
          list:res.data.data
        })
      }
    })
  },
  onLoad: function (options) {
  //在页面加载的时候运行获取热搜的方法
    this.getHotSearch()
  },
})

在这里插入图片描述

获取热门搜索,然后点击时会将对应的值进行传递,在搜索框,输入的值在点击搜索时会传递到获取歌曲列表页面

3.获取搜索歌曲

获取搜索歌曲:getSearchMusic.wxml

<!-- 一直存在的搜索框 -->
<van-search value="{{ value }}" label="" placeholder="请输入搜索关键词" use-action-slot="true" bind:change="onChange"
  bind:search="onSearch">
  <view slot="action" bind:tap="onClick">搜索</view>
</van-search>
<view style="margin-left:15px;font-weight:bold;">
搜索结果<van-tag style="margin-left:10px;margin-bottom:2px" type="success">单曲</van-tag>
</view>
<view wx:for="{{list}}" style="margin-left:15px">
  <van-row>
  <van-col span="4" >
    <image style="width:120rpx;height:120rpx;margin-top:8px" src="{{item.pic}}"></image>
  </van-col>
  <van-col span="20">
    <view 
          data-id="{{item.rid}}"
          data-albumpic="{{item.albumpic}}"
          data-time="{{item.songTimeMinutes}}" 
          data-artist="{{item.artist}}" 
          data-name="{{item.name}}"
          bindtap="playPageOnClick">
      <van-cell-group>
        <van-cell title="{{item.name}}" label="{{item.album}}" border="{{ false }}" />
      </van-cell-group>
    </view>
  </van-col>
</van-row>
</view>
获取搜索歌曲:getSearchMusic.js
// pages/getSearchMusic/getSearchMusic.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    value: '',
    name: '',
    list: null,
    rid: '',
    allRid: [],//列表歌曲的所有rid
    image:[],//图片
    singer:[],//歌手
    singname:[],//歌名
    alltime:[],//时间
    
  },
  //输入的内容
  onChange(e) {
    this.setData({
      value: e.detail,
    });
  },
  onClick: function () {
    var that = this
    wx.request({
      url: 'http://iecoxe.top:5000/v1/kuwo/search?key=' + this.data.value,
      success: function (res) {
        console.log(res)
        that.setData({
          //获取到名字用来渲染在搜索框
          list: res.data.data.list
        })
      }
    })
  },
  // 进行搜索并获取歌曲url
  playPageOnClick: function (e) {
    /**
     * 传递歌曲id用来获取歌曲url
     * 名字
     * 图片
     * 歌曲结束时间
     * 所有的rid
     */
    var rid = e.currentTarget.dataset.id
    var name = e.currentTarget.dataset.name
    var albumpic = e.currentTarget.dataset.albumpic
    var songTimeMinutes = e.currentTarget.dataset.time
    var artist = e.currentTarget.dataset.artist
    var ridList = this.data.allRid
    var singnames = this.data.singname
    var images = this.data.image
    var singers = this.data.singer
    var time = this.data.alltime
    wx.navigateTo({
      url: '../play/play?rid=' + rid + '&name=' + name + '&albumpic=' + albumpic + '&songTimeMinutes=' + songTimeMinutes + '&artist=' + artist+ '&ridList=' + ridList+ '&singnames=' + singnames+ '&images=' + images+ '&singers=' + singers+ '&alltime=' + time,
    })
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    var that = this;
    // 进行搜索并获取歌曲url  
    wx.request({
      url: 'http://iecoxe.top:5000/v1/kuwo/search?key=' + options.name,
      success: function (res) {
        console.log(res.data.data.list[0].rid)
        console.log(res.data.data.list[0].album)
        console.log(res.data.data.list[0].artist)
        //利用for循环来写入想要的数据 列表歌曲的所有rid
        for (let index = 0; index < res.data.data.list.length; index++) {
          var element = res.data.data.list[index].rid;
          var album = res.data.data.list[index].album;
          var artist = res.data.data.list[index].artist;
          var pic120 = res.data.data.list[index].pic120;
          var times = res.data.data.list[index].songTimeMinutes;
          var rid = 'allRid[' + index + ']';//歌名
          var albums = 'singname[' + index + ']';//歌名
          var artists = 'singer[' + index + ']';//歌手
          var pic = 'image[' + index + ']';//图片
          var time = 'alltime[' + index + ']';//图片
          that.setData({
            [rid]: element,
            [albums]: album,
            [artists]: artist,
            [pic]: pic120,
            [time]: times,
          });
        }
        that.setData({
          //获取到名字用来渲染在搜索框
          value: options.name,
          list: res.data.data.list
        })
      }
    })
  },
})

在这里插入图片描述

将获取到的搜索词进行网络请求,将回传的数据对页面进行渲染,当点击时,会附带数据进行点击回传到js跳转到播放页面,如歌曲的id,歌名,图片的地址等待,还有它们对应的数组,方便对下一曲和上一曲时使用。

4.播放页

播放页:play.wxml
<!--pages/play/play.wxml-->
<van-tabs class='selcetTab' bind:click="onClick_Tab" line-height="0px" title-active-color="red" swipeable="true">
  <van-tab title="歌曲" class="van-tabs">
    <!-- 歌手+歌名 -->
    <view style="width:100%;text-align:center;margin-bottom:10px">{{name}} - {{singer}}</view>
    <!-- 图片 --> 
    <view style="width:100%;text-align:center;margin-bottom:10px">
      <image  src="{{imageUrl}}" style="width:600rpx;height:600rpx;"></image>
    </view>
    
<!-- 进度条 -->
<view class="progressBar">
  <van-progress inactive percentage="{{percentage}}" 
  pivot-text=" " />
</view>
<!-- 进度条下面的数字 -->
<view class="progressBar">
  <van-row>
    <van-col span="12">{{minute}}:{{second}}</van-col>
    <van-col style="text-align:right" span="12">{{songTimeMinutes}}</van-col>
  </van-row>
</view>

<!-- 歌词 -->
<view class="lyric">
  
</view>

<!-- 播放器 -->
<view class="play">
<van-row>
    <!-- 播放模式 -->
    <van-col span="4">
      <image class="play_0" bindtap="bofangmoshi" src="../image/{{bofangmoshi}}.png"></image>
    </van-col>
    <!-- 上一曲 -->
    <van-col span="4">
      <image style="margin-left:20px" bindtap="last" class="play_1" src="../image/last.png"></image>
    </van-col>
    <!-- 播放 -->
    <van-col span="8">
      <image class="play_2" bindtap="playClick" src="../image/{{play}}.png"></image>
    </van-col>
    <!-- 下一曲 -->
    <van-col span="4">
      <image style="margin-right:20px" bindtap="next" class="play_1" src="../image/next.png"></image>
    </van-col>
    <!-- 播放列表 -->
    <van-col span="4">
      <image class="play_3" src="../image/liebiao.png"></image>
    </van-col>
  </van-row>
</view>

  </van-tab>
  <van-tab title="歌词">
    <view wx:for="{{lyrics}}" style="text-align:center;margin-bottom:10px">
  <view>{{item.lyric}}
  </view>
</view>
  </van-tab>
</van-tabs>
 播放页:play.wxss 
/* pages/play/play.wxss */
/* 标签页高度设置 */
.selectTab/deep/.van-tabs-line{
  height: 100%;
  
}
.selectTab/deep/.van-tabs-wrap{
  height: 100%;
}
/* 进度条 */

/* 进度条下面的数字 */
.progressBar{
  margin-top: 10px;
  padding-left: 25px;
  padding-right: 25px;
}
.play{
  text-align: center;
  margin-top: 10px;
  margin-bottom: 10px;
}
.play_0{
  width: 25px;
  height: 25px;
  margin-top: -5px;
}
.play_1{
  width: 25px;
  height: 25px;
}
.play_2{
  width: 40px;
  height: 40px;
  margin-top: -10px;
}
.play_3{
  width: 30px;
  height: 30px;
  margin-top: -3px;
}
/* lyric 歌词样式 */
.lyric{
  margin: 25px;
}
 播放页:play.js
// pages/play/play.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    //歌曲url
    Url: "",
    //歌名
    name: "",
    active: 1,
    boolean:true,//计时器判断
    lyrics: [],//歌词文字
    lyricsTime:[],
    //进度条数字
    number: '',
    bofangmoshi: 'liebiaobofang',
    play: 'suspend',
    percentage: 0, //进度条百分比
    songTimeMinutes: '', //歌曲结束时间
    minute: '0' + 0, // 分
    second: '0' + 0, // 秒
    allRidList: [], //所有rid的数组
    allSingNames: [], //所有歌名的数组
    allImage: [], //所有照片的数组
    allSinger: [], //所有歌手名的数组
    allTime: [], //所有歌手名的数组
    ridNumber: 0, //歌曲的rid位置,如果要下一曲就++
  },
  /**
   * 
   * 获取到时间,然后进行设置定时器,每1毫秒运行一次,当时间一直时,设置歌词,实现动态渲染
   */
  lyricsTime:function () {
    console.log(this.data.lyricsTime)
    var lyricsTimeInterval = setInterval(function () {
        
    },10)
  },
  /**
   * 进度条
   */
  time_percentage: function () {
    const that = this
    var time = this.data.songTimeMinutes //总时长
    var min = time.split(':')[0] //分
    var sec = time.split(':')[1] //秒
    var t = (Number(min * 60) + Number(sec)) * 10 //获得每百分之一对等的毫秒,用来制作计时器来推动百分比自增
    var percentage = this.data.percentage
    //进度条百分比设置
    var percentageInterval = setInterval(function () {
      percentage++
      if (percentage > 100) {
        //如果进度条=100时,置零
        that.setData({
          percentage: 0,
          play:'play',
          boolean:false
        })
        clearInterval(percentageInterval)
      } else {
        that.setData({
          percentage: percentage
        })
      }
    }, t)
    this.setData({
      percentageInterval: percentageInterval
    })
  },
  
  /**
   * 保证计时器能够成功的同时,获取到歌曲结束时间,接着时间到了自动暂停计时,然后置零
   */
  Time: function () { //计时器
    var songTimeMinutes = this.data.songTimeMinutes //总时长
    var min = songTimeMinutes.split(':')[0] //分
    var sec = songTimeMinutes.split(':')[1] //秒
    const that = this
    var second = this.data.second
    var minute = this.data.minute
    var timeIntervar = setInterval(function () { // 设置定时器
      second++

      //当分钟和秒数一致时
      if (minute == min) { //
        if (second == sec) {
          //置零
          second = 0
          that.setData({
            minute: '0' + 0
          })
          //停止计时
          clearInterval(timeIntervar)
          //执行下一首歌
          that.next()
        }
      }
      if (second >= 60) {
        second = 0 //  大于等于60秒归零
        minute++
        that.setData({
          minute: minute
        })
        if (minute >= 60) {
          minute = 0 //  大于等于60分归零
        }
        if (minute < 10) {
          // 少于10补零
          that.setData({
            minute: '0' + minute
          })
        } else {
          that.setData({
            minute: minute
          })
        }
      }
      if (second < 10) {
        // 少于10补零
        that.setData({
          second: '0' + second
        })
      } else {
        that.setData({
          second: second
        })
      }
    }, 1000)
    this.setData({
      timeIntervar: timeIntervar
    })
  },

  /**播放器
   * 播放模式
   * 上一曲
   * 播放暂停
   * 下一曲
   * 播放列表
   */
  //播放模式
  bofangmoshi: function () {
    if (this.data.bofangmoshi == 'liebiaobofang') {
      this.setData({
        bofangmoshi: "xunhuanbofang"
      })
    } else if (this.data.bofangmoshi == 'xunhuanbofang') {
      this.setData({
        bofangmoshi: "suijibofang"
      })
    } else if (this.data.bofangmoshi == 'suijibofang') {
      this.setData({
        bofangmoshi: "danquxunhuan"
      })
    } else if (this.data.bofangmoshi == 'danquxunhuan') {
      this.setData({
        bofangmoshi: "liebiaobofang"
      })
    }
  },
  //暂停播放
  pause:function () {
    this.data.innerAudioContext.pause()//暂停音乐
    this.setData({//更改图片
      play:'play',
      boolean:false,
    })
    //弹出提示
    wx.showToast({
      title: '暂停',
      icon: 'none',
    })
    //暂停计时器和进度条
    clearInterval(this.data.percentageInterval)
    clearInterval(this.data.timeIntervar)
  },
  play:function () {
    this.data.innerAudioContext.play()//暂停音乐
    this.setData({//更改图片
      play:'suspend',
      boolean:true,
    })
    //弹出提示
    wx.showToast({
      title: '播放',
      icon: 'none',
    })
    //继续进度条和计时器
    this.Time()
    this.time_percentage()
  },
  //暂停播放点击
  playClick: function () {
    var boolean = this.data.boolean
    if (boolean) {
      this.pause()
    } else {
      this.play()
    }
  },
  //上一曲
  last: function () {
    clearInterval(this.data.timeIntervar)
    clearInterval(this.data.percentageInterval)
    this.setData({
      minute: '0' + 0,
      second:'0' + 0,
      percentage:0
    })
    wx.showToast({
      title: '上一曲',
      icon: 'none',
    })
    //先销毁实例
    this.data.innerAudioContext.destroy()
    //通过更改url来改变歌曲的播放状态 首先获取到rid,默认为0 
    var lastRidNumber = this.data.ridNumber
    lastRidNumber--
    if (lastRidNumber < 0) { //当数字小于0时,那么重置为29
      this.setData({
        ridNumber: 29
      })
    }
    if (lastRidNumber >= 0) { //当大于等于0时,正常减
      this.setData({
        ridNumber: lastRidNumber
      })
    }
    var rid = this.data.allRidList[this.data.ridNumber]
    var name = this.data.allSingNames[this.data.ridNumber]
    var pic = this.data.allImage[this.data.ridNumber]
    var singer = this.data.allSinger[this.data.ridNumber]
    var time = this.data.allTime[this.data.ridNumber]
    if (name == '') {
      name = this.data.allSingNames[0]
    }
    if (this.data.play == 'play') {
      this.setData({
        play:'suspend',
        boolean:true,
      })
    }
    this.setData({
      name:name,
      singer:singer,
      imageUrl:pic,
      songTimeMinutes:time,
    })
   this.lyric(rid)//重新获取歌词
   this.getUrl(rid)//重新获取歌曲url
   this.Time()
   this.time_percentage()
  },
  //下一曲
  next: function () {
    clearInterval(this.data.timeIntervar)
    clearInterval(this.data.percentageInterval)
    this.setData({
      minute: '0' + 0,
      second:'0' + 0,
      percentage:0
    })
    wx.showToast({
      title: '下一曲',
      icon: 'none',
    })
    //先销毁实例
    this.data.innerAudioContext.destroy()
    //通过更改url来改变歌曲的播放状态 首先获取到rid,默认为0 
    var nextRidNumber = this.data.ridNumber
    nextRidNumber++
    /**
     * 因为数组有限,所以当大于30时置零
     */
    if (nextRidNumber > 29) { //当大于30时 置零
      this.setData({
        ridNumber: 0
      })
    }
    if (nextRidNumber <= 29) { //当小于等于29时,正常设置
      this.setData({
        ridNumber: nextRidNumber
      })
    }
    var rid = this.data.allRidList[this.data.ridNumber]
    var name = this.data.allSingNames[this.data.ridNumber]
    var pic = this.data.allImage[this.data.ridNumber]
    var singer = this.data.allSinger[this.data.ridNumber]
    var time = this.data.allTime[this.data.ridNumber]
    if (name == '') {
      name = this.data.allSingNames[0]
    }
    if (this.data.play == 'play') {
      this.setData({
        play:'suspend',
        boolean:true,
      })
    }
    this.setData({
      name:name,
      singer:singer,
      imageUrl:pic,
      songTimeMinutes:time,
    })
    this.lyric(rid)//重新获取歌词
    this.getUrl(rid)//重新获取歌曲url
    this.Time()
    this.time_percentage()
  },
  //标签页点击事件
  onClick_Tab(event) {

  },  
  //获取歌曲的歌词
  lyric: function (rid) {
    var that = this
    wx.request({
      url: 'http://iecoxe.top:5000/v1/kuwo/lyric?rid=' + rid, //这里填写你的接口路径
      success: function (res) {
        //先获取到歌词
        var lyric = res.data.lyric_str
        //对歌词进行分割
        lyric = lyric.split(']').map(item => item.split('['))
        //利用for循环来写入想要的数据
        for (let index = 0; index < lyric.length; index++) {
          const element = lyric[index][0];
          const time = lyric[index][1];
          var name = 'lyrics[' + index + '].lyric';
          var times = 'lyricsTime[' + index + '].time';
          that.setData({
            [name]: element,
            [times]:time
          });
        }
      }
    })
  },
  //获取歌曲url
  getUrl: function (rid) {
    var that = this
    wx.request({
      url: 'http://iecoxe.top:5000/v1/kuwo/song?rid=' + rid, //这里填写你的接口路径
      success: function (res) {
        console.log(res.data.url)
        console.log(res.statusCode)
        if (res.statusCode == 400) {
          wx.showToast({
            title: '该歌曲不存在或无法播放,请下一首',
            icon: 'none',
          })
        }
        console.log(res)
        that.myAudio(res.data.url)
      }
    })
  },
  //设置音乐播放器组件
  myAudio: function (url) {
    this.lyricsTime()
    const innerAudioContext = wx.createInnerAudioContext()
    //设置到data里面
    this.setData({
      innerAudioContext:innerAudioContext
    })
    //默认自动播放
    innerAudioContext.autoplay = true
    innerAudioContext.src = url
    innerAudioContext.onPlay(() => {
      wx.showToast({
        title: '开始播放',
        icon: 'none',
      })
    })
    innerAudioContext.onError((res) => {
      console.log(res.errMsg)
      console.log(res.errCode)
    })

  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    var n = options.ridList.split(',')
    var name = options.singnames.split(',')
    var image = options.images.split(',')
    var singer = options.singers.split(',')
    var time = options.alltime.split(',')
    this.setData({
      "rid": options.rid,
      name: options.name,
      imageUrl: options.albumpic,
      singer: options.artist,
      songTimeMinutes: options.songTimeMinutes,
      allRidList: n,
      allSingNames: name,
      allImage: image,
      allSinger: singer,
      allTime:time,
    })
    console.log(this.data.allTime)
    this.getUrl(options.rid) //歌曲rul
    this.lyric(options.rid) //歌词
    this.Time()//计时器
    this.time_percentage()//进度条
  },
  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {
    this.data.innerAudioContext.destroy()
  }

})

在这里插入图片描述
在这里插入图片描述

在播放页使用了wx.createInnerAudioContext()组件,因为官方的audio组件有很多bug,所以不对此进行使用,这个组件相对来说比较方便,也可以在后台播放,我在这里限制了不能让它离开了播放页还在播放,不然会有多重歌曲播放的bug,点击事件播放暂停没啥好说的,主要是计时器setInterval()的使用,在计时器这方面我对进度条包含在里面,当暂停时,进度条也会暂停,启动时也会启动,下一曲会清空进度条。

5.榜单列表页

榜单列表页:list.wxml
<!--pages/list/list.wxml-->
<view style="background-color:#FFFAF0">
  <view>
    <van-row>
      <van-col span="10">
        <image style="width:350rpx;height:300rpx" src="{{list.img}}"></image>
      </van-col>
      <van-col span="14">
        <view style="padding-top:15px;text-align: center;font-size:22px">{{name}}</view>
        <view style="padding-top:25px;padding-left:38px;">更新时间:
        </view>
        <view style="padding-top:5px;padding-left:38px;">{{list.pub}}</view>
      </van-col>
    </van-row>
  </view>
<view style="margin-top:10px;margin-left:15px" wx:for="{{list.musicList}}"
 bindtap="onClick" 
 data-id="{{item.albumid}}" 
 data-name="{{item.album}}" 
 data-artist="{{item.artist}}" 
  data-time="{{item.songTimeMinutes}}" 
 data-albumpic="{{item.albumpic}}">
  <van-row>
  <van-col span="6">
    <image style="width:150rpx;height:150rpx" src="{{item.albumpic}}"></image>
  </van-col>
  <van-col span="18">
    <!-- 歌名 -->
    <view>{{item.album}}</view>
    <view style="padding-top:15px;">{{item.artist}}</view>
  </van-col>
</van-row>
</view>
</view>
 榜单列表页:list.js
// pages/list/list.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    list:'',
    allRid: [],//列表歌曲的所有rid
    image:[],//图片
    singer:[],//歌手
    singname:[],//歌名
    alltime:[],//时间
  },
  onClick:function (e) { 
    var rid = e.currentTarget.dataset.id
    var name = e.currentTarget.dataset.name
    var albumpic = e.currentTarget.dataset.albumpic
    var songTimeMinutes = e.currentTarget.dataset.time
    var artist = e.currentTarget.dataset.artist
    var ridList = this.data.allRid
    var singnames = this.data.singname
    var images = this.data.image
    var singers = this.data.singer
    var time = this.data.alltime
    wx.navigateTo({
      url: '../play/play?rid=' + rid + '&name=' + name + '&albumpic=' + albumpic + '&songTimeMinutes=' + songTimeMinutes + '&artist=' + artist+ '&ridList=' + ridList+ '&singnames=' + singnames+ '&images=' + images+ '&singers=' + singers+ '&alltime=' + time,
    })
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    var that = this
    console.log(options.id)
    console.log(options.name)
    wx.request({
      url: 'http://iecoxe.top:5000/v1/kuwo/top?topId='+options.id,
      success:function (res) {
        console.log(res.data.data)
         //利用for循环来写入想要的数据 列表歌曲的所有rid
         for (let index = 0; index < res.data.data.musicList.length; index++) {
          var element = res.data.data.musicList[index].albumid;
          var album = res.data.data.musicList[index].album;
          var artist = res.data.data.musicList[index].artist;
          var pic120 = res.data.data.musicList[index].pic120;
          var times = res.data.data.musicList[index].songTimeMinutes;
          var rid = 'allRid[' + index + ']';//id
          var albums = 'singname[' + index + ']';//歌名
          var artists = 'singer[' + index + ']';//歌手
          var pic = 'image[' + index + ']';//图片
          var time = 'alltime[' + index + ']';//图片
          that.setData({
            [rid]: element,
            [albums]: album,
            [artists]: artist,
            [pic]: pic120,
            [time]: times,
          });
        }
        that.setData({
          name:options.name,
          list:res.data.data
        })
      }
    })
  },

})

在这里插入图片描述

将传递过来的歌单id进行发送请求,用返回的数据将页面渲染,点击时传递对应的歌曲id,歌名等数据进行跳转到播放页,并且将数组传递,唯一不足的地方,就是上下一曲时,最多只能30首歌。

6.对应页面的json文件

因为使用了框架就需要在json文件中引入对应的库,所以我在编写的过程中并没有写在app.json中,在这里建议大家直接丢到app.json中,如果有重复的删了就是了

//index.json
{
  "usingComponents": {
    "van-search": "@vant/weapp/search/index",
    "van-notice-bar": "@vant/weapp/notice-bar/index",
    "van-tab": "@vant/weapp/tab/index",
    "van-tabs": "@vant/weapp/tabs/index",
    "van-count-down": "@vant/weapp/count-down/index"
  }
}
//search.json
{
  "usingComponents": {
    "van-search": "@vant/weapp/search/index"
  }
}
//getSearchMusic.json
{
  "usingComponents": {
    "van-search": "@vant/weapp/search/index",
    "van-cell": "@vant/weapp/cell/index",
    "van-cell-group": "@vant/weapp/cell-group/index",
    "van-row": "@vant/weapp/row/index",
    "van-col": "@vant/weapp/col/index",
    "van-button": "@vant/weapp/button/index",
    "van-tag": "@vant/weapp/tag/index"
  }
}
//play.json
{
  "usingComponents": {
    "van-tab": "@vant/weapp/tab/index",
    "van-tabs": "@vant/weapp/tabs/index",
    "van-progress": "@vant/weapp/progress/index",
    "van-row": "@vant/weapp/row/index",
    "van-col": "@vant/weapp/col/index",
    "van-slider": "@vant/weapp/slider/index",
    "van-sticky": "@vant/weapp/sticky/index"
  }
}
//list.json
{
  "usingComponents": {
  "van-card": "@vant/weapp/card/index"
  }
}

总结

以上就是我要给大家带来的内容,本文仅仅简单介绍了这个小项目的一部分,还有很多很多的功能没有进行优化,也有很多遗憾没有实现,本文所有代码都是自己手敲的,命名规则比较混乱。你有更好的建议,欢迎进行评论。你有什么困惑,也可以添加我的个人QQ:643895437,欢迎和大家探讨问题。

再次声明,该api是另外一个博主的,up本身并没有api。
感谢你能看到这里,如果觉得这篇文章对你有所帮助,请给我点个赞吧,谢谢啦。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值