/** * 用户点击右上角分享 */ onShareAppMessage: function ({from}) { // f_网易云小程序实现自动播放">
当前位置:   article > 正文

微信小程序【网易云音乐实战】(第五篇 转发分享、每日推荐、音乐播放、页面通信npm包、进度条、全局数据)_网易云小程序实现自动播放

网易云小程序实现自动播放

一、转发分享功能

onShareAppMessage(Object object)
在这里插入图片描述

在这里插入图片描述

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

<button open-type="share" class="item btn">
    <text class="iconfont icon-gengduo"></text>
</button>
  • 1
  • 2
  • 3
  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function ({from}) {
    // from为 menu表示页面转发,button表示按钮转发
    console.log(from);
    if(from === "button"){
      return {
        title:"来自button的转发",
        page:"/pages/video/video",
        imageUrl:"/static/images/nvsheng.jpg"
      }
    }else{
      return {
        title:"来自menu的转发",
        page:"/pages/video/video",
        imageUrl:"/static/images/nvsheng.jpg"
      }
    }
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

在这里插入图片描述

如果要分享给小伙伴体验,需要在小程序的 成员管理 —> 添加体验成员


二、每日推荐歌曲

接口:
在这里插入图片描述

在这里插入图片描述

<view class="recommendSongContainer">
    <!--  头部  -->
    <view class="header">
        <image src="/static/images/recommendSong/recommendSong.jpg"></image>
        <view class="date">
            <text class="day">{{day}} / </text>
            <text class="month">{{month}}</text>
        </view>
    </view>

    <!--   列表区域 -->
    <view class="ListContainer">
        <view class="listHeader">
            <text>播放全部</text>
            <text class="changeMore">多选</text>
        </view>

        <!--   内容区     -->
        <scroll-view scroll-y class="listScroll">
            <view class="scrollItem" wx:for="{{recommendList}}" wx:key="id">
                <image src="{{item.album.picUrl}}"></image>
                <view class="musicInfo">
                    <text class="musicName">{{item.name}}</text>
                    <text class="author">{{item.artists[0].name}}</text>
                </view>
                <text class="iconfont icon-gengduo"></text>
            </view>
        </scroll-view>
    </view>

</view>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

.recommendSongContainer .header{
    position: relative;
    width: 100%;
    height: 300rpx;
}

.recommendSongContainer .header image{
    width: 100%;
    height: 100%;
}

.recommendSongContainer .header .date{
    position: absolute;
    left: 50%;
    top: 50%;
    margin-left: -150rpx;
    margin-top: -50rpx;

    width: 300rpx;
    height: 100rpx;
    text-align: center;
    line-height: 100rpx;
    color: #FFF;
}

.header .date .day{
    font-size: 40rpx;
}

/* 列表区域的样式  */
.ListContainer{
    position: relative;
    top: -20rpx;
    padding: 0 20rpx;
    border-radius: 30rpx;
    background: #FFF;
}

.listHeader{
    height: 80rpx;
    line-height: 80rpx;
}

.listHeader .changeMore{
    float: right;
}

/* 列表内容区样式*/
.listScroll{
    width: 100%;
    height: calc(100vh - 380rpx);
}

.scrollItem{
    display: flex;
    position: relative;
    margin-bottom: 20rpx;
}

.scrollItem image{
    width: 80rpx;
    height: 80rpx;
    border-radius: 8rpx;
}

.musicInfo{
    display: flex;
    flex-direction: column;
    margin-left: 20rpx;
    max-width: 400rpx;
}

.musicInfo text{
    height: 40rpx;
    line-height: 40rpx;
    font-size: 24rpx;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.scrollItem .iconfont{
    position: absolute;
    right: 0;
    width: 80rpx;
    height: 80rpx;
    line-height: 80rpx;
    text-align: right;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 判断用户是否登录
    let userInfo = wx.getStorageSync("userInfo");
    if(!userInfo){
      wx.showToast({
        title:"请先登录",
        icon:"none",
        success:()=>{
          // 跳转到登录界面
          wx.reLaunch({
            url:"/pages/login/login"
          })
        }
      })
    }

    // 更新日期
    this.setData({
      day:new Date().getDate(),
      month:new Date().getMonth()+1
    });

    // 获取每日推荐的数据
    this.getRecommendList()
  },

  // 获取用户每日推荐数据
  async getRecommendList() {
    let recommendList = await request("/recommend/songs");
    this.setData({
      recommendList: recommendList.recommend
    })
  },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

三、音乐播放

在这里插入图片描述

知识点:

旋转样式:

transform-origin: 40rpx 0; /* 旋转中心*/
transform: rotate(-20deg); /* 旋转角度*/
transition: transform 1s; /* 旋转过过渡动画 */
  • 1
  • 2
  • 3

class的动态控制:

方式一:&&
<image class="needle {{isPlay && 'needleRotate'}}" src=""></image>
方式二:三元运算
<image class="needle {{isPlay?'needleRotate':''}}" src=""></image>
  • 1
  • 2
  • 3
  • 4

旋转动画:

/* 磁盘的动画 : infinite 无限循环*/
.discAnimation{
    animation: disc 4s linear infinite;
    animation-delay: 1s; /* 动画延迟1s 当遥感到位旋转*/
}
/* @keyframes :设置帧动画
1) from to:
    使用与简单的动画,只有起始帧和结束帧
2) 百分比
    多用于复杂的动画,动画不止两帧
*/
@keyframes disc {
    from{
        transform:rotate(0deg);
    }
    to{
        transform:rotate(360deg);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
<view class="discContainer {{isPlay && 'discAnimation'}}">
  • 1

1. 路由页面 跳转 传参

知识点1:

点击事件传参数 : data-key=valuse

<view data-song="{{item}}" bindtap="toSongDetail">
  • 1

响应函数接参数:let x = event.currentTarget.dataset.key;

let song = event.currentTarget.dataset.song;
  • 1

知识点2:

路由页面跳转 传参数:url:"***?song="+song
JSON.stringify(song)先要将对象转换成字符串

// 路由跳转传参:query 参数
wx.navigateTo({
      url:"***?song="+ JSON.stringify(song) // 
})
  • 1
  • 2
  • 3
  • 4

路由跳转页面接收参数:

onLoad: function (options) {
  // 1. options:用于接收路由跳转的query参数
  // 2. 原生小程序中路由传参,对参数的长度有限制,如果参数过长会自动截取掉
  console.log(options)
},
  • 1
  • 2
  • 3
  • 4
  • 5

由于通过上面的方法item一项的数据很大,所有在传参的时候会自动截取掉,所有实践中传 歌曲的id过去。

2. 获取详情歌曲数据

在这里插入图片描述

页面传参:

  // 点击歌曲 跳转不同的详情页
  toSongDetail(event){
    // 接收参数
    let song = event.currentTarget.dataset.song;
    // 路由跳转传参:query 参数
    wx.navigateTo({
      url:"/pages/songDetail/songDetail?musicId="+ song.id
    })
  },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

接收参数:

onLoad: function (options) {
  // 1. options:用于接收路由跳转的query参数
  // 2. 原生小程序中路由传参,对参数的长度有限制,如果参数过长会自动截取掉
  let musicId = options.musicId
},
  • 1
  • 2
  • 3
  • 4
  • 5

获取歌曲详情:

// 获取音乐的详情的功能函数
async getMusicInfo(musicId) {
  let songData = await request("/song/detail",{ids:musicId})
  this.setData({
    song:songData.songs[0]
  })
},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

3. 动态设置页面标题

wx.setNavigationBarTitle(Object object)

在这里插入图片描述

// 动态修改窗口的标题
wx.setNavigationBarTitle({
  title:this.data.song.name
})
  • 1
  • 2
  • 3
  • 4

4. 音乐播放和暂停

背景音频 :BackgroundAudioManager

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4.1 播放 和 暂停

后台播放需要设置:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

代码:

  // 控制音乐播放/暂停的功能函数
  async musicControl(isPlay, musicId) {
    let backgroundAudioManager = wx.getBackgroundAudioManager();
    if (isPlay == true) { // 音乐播放
      console.log("播放!");
      // 获取播放链接
      let musicLickData = await request("/song/url", {id: musicId});
      let musicLick = musicLickData.data[0].url;
      backgroundAudioManager.src = musicLick; // 添加音乐播放链接
      backgroundAudioManager.title = this.data.song.name;
    } else { // 音乐暂停
      console.log("暂停!");
      backgroundAudioManager.pause(); // 音乐暂停
    }
  },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

5. 决解系统任务栏控制音乐播放状态显示不一致问题

BackgroundAudioManager

当用户点击系统的控制栏时,小程序没有检测到

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

/**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    /* 问题: 如果用户操作系统的控制音乐或者暂停的按钮,页面不知道,导致页面显示是否播放的状态和真实的音乐播放状态不一致
    *  解决方案:
    *     1. 通过控制音频的实例 backgroundAudioManager 去监听音乐播放/暂停
    *
    * */
    // 创建音乐控制播放实例
    this.backgroundAudioManager = wx.getBackgroundAudioManager();
    // 监听音乐播放/暂停/停止
    this.backgroundAudioManager.onPlay(()=>{
      this.changePlayState(true);
    });
    this.backgroundAudioManager.onPause(()=>{
      this.changePlayState(false);
    });
    this.backgroundAudioManager.onStop(()=>{
      this.changePlayState(false);
    });
  },

  // 修改播放状态的功能函数
  changePlayState(isPlay){
    this.setData({
      isPlay:isPlay
    })
  },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

6. getApp决解页面销毁音乐播放状态问题

AppObject getApp(Object object)

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

在这里插入图片描述

全局保存音乐播放数据:
app.js

App({

  globalData:{
    isMusicPlay:false, // 全局标识是否有音乐播放
    musicId:"", // 音乐id
  },
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

songDetail.js

// 获取全局实例
const appInstance = getApp();
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    let musicId = options.musicId;
    this.setData({
      musicId:musicId
    });
    // 获取音乐详情
    this.getMusicInfo(musicId);

    /* 问题: 如果用户操作系统的控制音乐或者暂停的按钮,页面不知道,导致页面显示是否播放的状态和真实的音乐播放状态不一致
    *  解决方案:
    *     1. 通过控制音频的实例 backgroundAudioManager 去监听音乐播放/暂停
    *
    * */
    // 判断当前音乐是否在播放
    if(appInstance.globalData.isMusicPlay && appInstance.globalData.musicId === musicId){
      // 修改当前页面音乐播放状态为true
      this.setData({
        isPlay:true
      });
    }

    // 创建音乐控制播放实例
    this.backgroundAudioManager = wx.getBackgroundAudioManager();
    // 监听音乐播放/暂停/停止
    this.backgroundAudioManager.onPlay(()=>{
      this.changePlayState(true);
      appInstance.globalData.musicId=musicId;
    });
    this.backgroundAudioManager.onPause(()=>{
      this.changePlayState(false);
    });
    this.backgroundAudioManager.onStop(()=>{
      this.changePlayState(false);
    });
  },

  // 修改播放状态的功能函数
  changePlayState(isPlay){
    this.setData({
      isPlay:isPlay
    });
    // 修改全局音乐播放的状态
    appInstance.globalData.isMusicPlay=isPlay;
  },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

7. 通过页面通信,npm包的使用

7.1 小程序使用 npm 包

1. 初始化 package.json

npm init或者 npm init -y
在这里插入图片描述
一直回车就好了

在这里插入图片描述
生成的这个package.json可以看作这个项目的说明书

2. 勾选允许使用 npm
在这里插入图片描述

3. 下载 npm包

npm install packageName

4. 构建 npm

  1. 开发者工具 --> 工具 --> 构建 npm
  2. 会自动将 node_modules 中的包,打包到 miniprogram_npm 中在这里插入图片描述

7.2 pubsub消息订阅发布,自定义事件说明

pubsun包可以帮助完成页面与页面之间的通信!

https://github.com/mroderick/PubSubJS
Install via npm (npm install pubsub-js)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

7.3 页面通信实现

recommendSong 与 songDetail界面通信!
在这里插入图片描述

recommendSong.js

onLoad: function (options) {
......其他代码

    // ** 订阅(绑定)来自songDetail 页面发布的消息
    PubSub.subscribe("switchType",(msg,data)=>{
      let {recommendList,index} = this.data;
      if(data === "pre"){ // 上一首
        index-=1;
        if(index==-1) index=recommendList.length-1;
      }else{ // 下一首
        index=(index+1)%recommendList.length;
      }
      this.setData({
        index:index
      })
      let musicId = recommendList[index].id; // 将要更新的id
      // 将musicId 回传给songDetail页面
      PubSub.publish("musicId",musicId);
    });
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

songDetail.js

  // 点击切换歌曲回调函数
  handleSwitch(event){
    // 获取切换的类型
    let type = event.currentTarget.id;
    // 发布消息数据给recommendSong页面
    PubSub.publish("switchType",type);

    // 接收musicId
    PubSub.subscribe("musicId",(msg,data)=>{
      console.log(msg,data);
      // 取消订阅
      PubSub.unsubscribe("musicId"); 
    });
  },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

8. 歌曲进度条

知识点1:

http://momentjs.cn/ 专门处理时间的库

npm install moment
在这里插入图片描述
引入包需要 构建一下

 // songData.data.dt 就是总时长( 毫秒)
 let durationTime = moment(songData.songs[0].dt).format("mm:ss");
  • 1
  • 2

知识点2:

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

 <!--  进度条控制区域  -->
 <view class="programControl">
     <text>{{currentTime}}</text>
     <!--  总的进度条   -->
     <view class="barControl">
         <!--  实时的进度条  -->
         <view class="audio-currentTime-Bar" style="width: {{currentWidth+'rpx'}}">
             <!--  小圆球 -->
             <view class="audio-circle"></view>
         </view>
     </view>
     <text>{{durationTime}}</text>
 </view>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
/* 进度条控制区域 */
.programControl{
    position: absolute;
    width: 640rpx;
    height: 80rpx;
    bottom: 200rpx;
    line-height: 80rpx;
    display: flex;
}

.barControl{
    position: relative;
    width: 430rpx;
    height: 4rpx;
    margin: auto;
    background: rgba(0,0,0,0.4);
}
.audio-currentTime-Bar{
    position: absolute;
    top: 0;
    left: 0;
    z-index: 1;
    height: 4rpx;
    background: red;
}
/* 小圆球*/
.audio-circle{
    position: absolute;
    right: -12rpx;
    top: -4rpx;
    width: 12rpx;
    height: 12rpx;
    border-radius: 50%;
    background: #ffffff;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
data: {
  currentTime:"00:00", //实时的时间
  durationTime:"00:00", // 歌曲总时长
  currentWidth:0, // 实时播放长度
},
  
onLoad: function (options) {
    // 监听背景音频播放进度更新事件,只有小程序在前台时会回调。
    this.backgroundAudioManager.onTimeUpdate(()=>{
      let currentTime = moment(this.backgroundAudioManager.currentTime*1000).format("mm:ss");
      let currentWidth = (this.backgroundAudioManager.currentTime/this.backgroundAudioManager.duration) * 430;
      this.setData({
        currentTime:currentTime,
        currentWidth:currentWidth
      });
    });
},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

9. 一首播放完成自动切换下一首

// 监听音乐播放自然结束
this.backgroundAudioManager.onEnded(()=>{
  // 自动切换下一首,自动播放
  PubSub.publish("switchType","next");
  // 进度条恢复 0
  this.setData({
    currentWidth:0,
    currentTime:"00:00", //实时的时间
  })
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在这里插入图片描述

今天拼多多赚了100 费了九牛二虎之力。。。直接卸载软件。。。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/77856
推荐阅读
相关标签
  

闽ICP备14008679号