ToB企服应用市场:ToB评测及商务社交产业平台

标题: 【微信小程序学习】网易云音乐歌曲详情页代码实现 [打印本页]

作者: 雁过留声    时间: 2022-6-25 00:15
标题: 【微信小程序学习】网易云音乐歌曲详情页代码实现
这里记录一下做网易云小程序的音乐播放详情页面的代码。
音乐播放界面的主要的重点有几个:
  1、磁盘和摇杆的旋转效果,这里运用了css的动画属性
  2、音乐播放和暂停,下一首/上一首等播放效果的实现
  3、进度条的样式和控制
  4、和上一页音乐推荐列表页通信,利用订阅与发布Pubsub

   HTML代码及要点
  1. <view class="songDetailContainer">
  2.   <view class="author">{{song.ar[0].name}}</view>
  3.   <view class="circle"></view>
  4.   <image class="needle {{isPlay?'needleRotate':''}}" src="/static/images/song/needle.png"></image>
  5.   <view class="discContainer {{isPlay?'discAnimation':''}}">
  6.    <image class="disc" src="/static/images/song/disc.png"></image>
  7.    <image class="musicImg" src="{{song.al.picUrl}}"></image>
  8.   </view>
  9.   
  10.   <view class="progressControl">
  11.     <text>{{currentTime}}</text>
  12.    
  13.     <view class="barControl">
  14.       
  15.       <view class="audio-currentTime-Bar" style="width: {{currentWidth + 'rpx'}}">
  16.         
  17.         <view class="audio-circle"></view>
  18.       </view>
  19.     </view>
  20.     <text>{{durationTime}}</text>
  21.   </view>
  22.   
  23.   <view class="musicControl">
  24.     <text class="iconfont icon-iconsMusicyemianbofangmoshiShuffle"></text>
  25.     <text class="iconfont icon-shangyishou" id="pre" bindtap="handleSwitch"></text>
  26.     <text class="iconfont {{isPlay?'icon-zanting': 'icon-bofang'}} big" bindtap="handleMusicPlay"></text>
  27.     <text class="iconfont icon-next" id="next" bindtap="handleSwitch"></text>
  28.     <text class="iconfont icon-iconsMusicyemianbofangmoshiPlayList"></text>
  29.   </view>
  30. </view>
复制代码
HTML要点: 


 
这里利用了三元表达式,当isPlay为true时,摇杆、磁盘和播放按钮就会开始启动动画,否则相反。

 实时进度条的动画利用了红色实时进度条的宽度的变化风格。
    CSS代码及要点
  1. /* pages/songDetail/songDetail.wxss */
  2. @import "/static/iconfont/iconfont.wxss";
  3. page {
  4.   height: 100%;
  5. }
  6. .songDetailContainer{
  7.   height: 100%;
  8.   background: rgba(0,0,0,0.5);
  9.   display: flex;
  10.   flex-direction: column;
  11.   align-items: center;
  12. }
  13. /* 底座 */
  14. .circle {
  15.   position: relative;
  16.   z-index: 100;
  17.   width: 60rpx;
  18.   height: 60rpx;
  19.   border-radius: 50%;
  20.   background: #fff;
  21.   margin: 10rpx 0;
  22. }
  23. /* 摇杆 */
  24. .needle{
  25.   position: relative;
  26.   z-index: 99;
  27.   top:-40rpx;
  28.   left: 60rpx;
  29.   width:192rpx;
  30.   height:274rpx;
  31.   /* 要先设置好旋转的中心点 */
  32.   transform-origin:40rpx 0;
  33.   transform: rotate(-20deg);
  34.   transition: transform 1s;
  35.   
  36. }
  37. /* 播放时摇杆动画 */
  38. .needleRotate{
  39.   transform: rotate(0deg);
  40. }
  41. /* 磁盘 */
  42. .discContainer{
  43.   position: relative;
  44.   top:-170rpx;
  45.   width: 598rpx;
  46.   height: 598rpx;
  47. }
  48. .discAnimation{
  49.   animation: disc 3s linear infinite;
  50.   animation-delay:1s;
  51. }
  52. /*
  53.   @keyframes:设置动画帧
  54.   1、from to
  55.     使用于简单的动画,只有起始帧和结束帧
  56.   
  57.   2、百分比
  58.     多用于复杂的动画,动画不止两帧
  59. */
  60. @keyframes disc{
  61.   from{
  62.     transform: rotate(0deg);
  63.   }
  64.   to{
  65.     transform: rotate(360deg);
  66.   }
  67. }
  68. .disc{
  69.   width: 598rpx;
  70.   height: 598rpx;
  71. }
  72. .musicImg{
  73.   position: absolute;
  74.   top:0;
  75.   right:0;
  76.   bottom:0;
  77.   left:0;
  78.   margin: auto;
  79.   width: 370rpx;
  80.   height: 370rpx;
  81.   border-radius: 50%;
  82. }
  83. /* 底部控制区域 */
  84. .musicControl {
  85.   position: absolute;
  86.   bottom: 40rpx;
  87.   left: 0;
  88.   border-top: 1rpx solid #fff;
  89.   width: 100%;
  90.   display: flex;
  91. }
  92. .musicControl  text {
  93.   width: 20%;
  94.   height: 120rpx;
  95.   line-height: 120rpx;
  96.   text-align: center;
  97.   color: #fff;
  98.   font-size: 50rpx;
  99. }
  100. .musicControl  text.big{
  101.   font-size: 80rpx;
  102. }
  103. /* 进度条控制区域 */
  104. .progressControl {
  105.   position: absolute;
  106.   bottom: 200rpx;
  107.   width: 640rpx;
  108.   height: 80rpx;
  109.   line-height: 80rpx;
  110.   display: flex;
  111. }
  112. .barControl {
  113.   position: relative;
  114.   width: 450rpx;
  115.   height: 4rpx;
  116.   background: rgba(0, 0, 0, 0.4);
  117.   margin: auto;
  118. }
  119. .audio-currentTime-Bar {
  120.   position: absolute;
  121.   top: 0;
  122.   left: 0;
  123.   z-index: 1;
  124.   height: 4rpx;
  125.   background: red;
  126. }
  127. /* 小圆球 */
  128. .audio-circle {
  129.   position: absolute;
  130.   right: -12rpx;
  131.   top: -4rpx;
  132.   width: 12rpx;
  133.   height: 12rpx;
  134.   border-radius: 50%;
  135.   background: #fff;
  136. }
复制代码
CSS要点: 
 

这里利用了transform动画,首先设置好旋转的中心点,利用transform-origin属性, 上方图片红框代表摇杆图片的范围,蓝色点为需要旋转的中心点,位置为x坐标为40rpx,纵坐标为0。摇杆要从原来的图片位置逆时针转动20度,所以设定为transform:rotate(-20deg)。加上过渡效果,利用transition:transform 1s。

磁盘的转动利用了css里的animation,linear代表线性,infinite代表一直动。
要设置动画帧@keyframes,从0度到360度,代表了磁盘的旋转。 
    JS代码及要点
  1. // pages/songDetail/songDetail.js
  2. import request from '../../../utils/request'
  3. import PubSub from 'pubsub-js'
  4. import moment from 'moment'
  5. //获取全局实例
  6. const appInstance = getApp();
  7. Page({
  8.   /**
  9.    * 页面的初始数据
  10.    */
  11.   data: {
  12.      isPlay:false,  //播放状态
  13.      song:{},//歌曲详情对象
  14.      musicId:'', //音乐id
  15.      musicLink:'',//音乐的链接
  16.      currentTime:'00:00',//实时时间
  17.      durationTime:'00:00',//总时长
  18.      currentWidth:0, //实时进度条宽度
  19.   },
  20.   /**
  21.    * 生命周期函数--监听页面加载
  22.    */
  23.   onLoad: function (options) {
  24.     //options:用于接收路由跳转的query参数
  25.     //原生小程序中路由传参,对参数的长度有限制,如果长度过长会自动截取掉
  26.    
  27.     // console.log(options)
  28.     // console.log(musicId)
  29.     let musicId = options.musicId;
  30.     this.setData({
  31.       musicId
  32.     })
  33.     //获取音乐详情
  34.     this.getMusicInfo(musicId);
  35.     /**
  36.      * 问题:如果用户操作系统的控制音乐播放/暂停的按钮,页面不知道,导致页面是否播放的状态和真实的音乐播放状态不一致
  37.      * 解决方案:
  38.      *   通过控制音频的实例backgroundAudioManager 去监视音乐暂停播放/暂停
  39.      */
  40.     //判断当前页面音乐是否在播放
  41.     if(appInstance.globalData.isMusicPlay && appInstance.globalData.musicId
  42.      === musicId){
  43.        //修改当前页面音乐播放状态为true
  44.        this.setData({
  45.          isPlay:true
  46.        })
  47.     }
  48.     //创建控制音乐播放的实例
  49.     this.backgroundAudioManager = wx.getBackgroundAudioManager();
  50.     //监视音乐播放/暂停/停止
  51.     this.backgroundAudioManager.onPlay(()=>{
  52.       //修改音乐是否播放的状态
  53.       this.changePlayState(true);
  54.       //修改全局音乐播放的状态
  55.       appInstance.globalData.musicId = musicId;
  56.     });
  57.     this.backgroundAudioManager.onPause(() => {
  58.       this.changePlayState(false);   
  59.     });
  60.     this.backgroundAudioManager.onStop(() => {
  61.       this.changePlayState(false);   
  62.     });
  63.     //监听音乐自然播放结束
  64.     this.backgroundAudioManager.onEnded(() => {
  65.      //自动切换至下一首音乐,并且自动播放
  66.       PubSub.publish('switchType','next')
  67.      //将实时进度条还原成0
  68.      this.setData({
  69.        currentWidth:0,
  70.        currentTime: '00:00'
  71.      })
  72.     })
  73.     //监听音乐实时播放的进度
  74.     this.backgroundAudioManager.onTimeUpdate(()=>{
  75.       //格式化实时播放时间
  76.       let currentTime = moment(this.backgroundAudioManager.currentTime*1000).format('mm:ss')
  77.       let currentWidth = this.backgroundAudioManager.currentTime / this.backgroundAudioManager.duration*450
  78.       this.setData({
  79.         currentTime,
  80.         currentWidth
  81.       })
  82.     })
  83.   },
  84.   //修改播放状态的功能函数
  85.   changePlayState(isPlay){
  86.     this.setData({
  87.       isPlay
  88.     })
  89.     //修改全局音乐播放的状态
  90.     appInstance.globalData.isMusicPlay = isPlay;
  91.   },
  92.   //获取音乐详情的功能函数
  93.   async getMusicInfo(musicId){
  94.     let songData = await request('/song/detail',{ids:musicId});
  95.     //songData.songs[0].dt 单位ms
  96.     let durationTime = moment(songData.songs[0].dt).format('mm:ss')
  97.     this.setData({
  98.       song:songData.songs[0],
  99.       durationTime
  100.     })
  101.     //动态修改窗口标题
  102.     wx.setNavigationBarTitle({
  103.       title:this.data.song.name
  104.     })
  105.   },
  106.   //点击播放/暂停的回调
  107.   handleMusicPlay(){
  108.     let isPlay = !this.data.isPlay;
  109.     // //修改是否播放的状态
  110.     // this.setData({
  111.     //   isPlay
  112.     // })
  113.     let {musicId,musicLink} = this.data;
  114.     this.musicControl(isPlay,musicId,musicLink);
  115.   },
  116.   
  117.   //控制音乐播放/暂停的功能函数
  118.   async musicControl(isPlay, musicId, musicLink){
  119.    
  120.       if(isPlay){  //音乐播放
  121.         if(!musicLink){
  122.           //获取音乐播放链接
  123.           let musicLinkData = await request('/song/url', { id: musicId });
  124.           musicLink = musicLinkData.data[0].url;
  125.           this.setData({
  126.             musicLink
  127.           })
  128.         }
  129.       
  130.       this.backgroundAudioManager.src = musicLink;
  131.       this.backgroundAudioManager.title = this.data.song.name;
  132.      }else{  //暂停音乐      
  133.       this.backgroundAudioManager.pause();
  134.      }
  135.   },
  136.   //点击切换上一首下一首的回调
  137.   handleSwitch(event){
  138.     //获取切歌的类型
  139.     let type = event.currentTarget.id;
  140.     //关闭当前播放的音乐
  141.     this.backgroundAudioManager.stop()
  142.     //订阅来自recommendsong页面发布的musicId消息
  143.     PubSub.subscribe('musicId',(msg,musicId)=>{
  144.        // console.log(musicId)
  145.    
  146.     //获取音乐详情信息
  147.     this.getMusicInfo(musicId)
  148.     //自动播放切换的当前音乐
  149.     this.musicControl(true,musicId)
  150.     //取消订阅
  151.     PubSub.unsubscribe('musicId')
  152.     })
  153.     //发布消息数据给recommendSong
  154.     PubSub.publish('switchType',type)
  155.   },
  156. })
复制代码
JS要点: 
 全局数据放在app.js中:

 
这里利用了 



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4