仿网易云音乐-音乐播放歌词展示,歌词滚动,旋转唱片,和时长进度条

 

<view class="m-song-bg"  
style="background-image: url({{songDetail.al.picUrl}});filter: blur(30px);">
</view>
<view>
                    <view class='m-song-wrap  {{playStatus?"z-playing":"z-pausing"}}'>
                        <view class="m-song-disc">
                            <view class="m-song-turn">
                                <view class="m-song-rollwrap">
                                    <view class='m-song-img a-circling' style="animation-play-state:{{state}}">
                                    <image class="u-img" alt="song-img" src="{{ songDetail.al.picUrl }}"></image>
                                </view>
                            </view>
                            <view class="m-song-lgour">
                                <view class="m-song-light a-circling" style="animation-play-state:{{state}}">
                                
                                </view>
                            </view>
                        </view>
                        <text wx:if="{{!playStatus}}" class="m-song-plybtn"></text>
                    </view>
                    <view class="m-song-clickarea" bindtap="playOrpause"></view>
                </view>
</view>
播放音乐代码
var requestUrl = require('../../utils/request.js')
Page({

  /**
   * 页面的初始数据
   */
  data: {
    palyMusicUrl: ' ',
    playTitle:' ',
    music:null,
    songDetail: null,
    playStatus: true,
    state: ' ',
  },
  playMusic: function () {
    // const music = wx.createInnerAudioContext()
    const music = wx.getBackgroundAudioManager()
    let that = this;
    that.setData({
      music: music
    });

    music.autoplay = true;
    music.src = this.data.palyMusicUrl;
    music.title=this.data.playTitle;
    // console.log(this.data.palyMusicUrl)
  
    
    music.onPlay(() => {
      that.setData({
        playStatus: true,
        state: ' '
      })
      this.setCurrentIndex();
    });
    music.onPause(() => {
      console.log('pause');
      that.setData({
        playStatus: false,
        state: 'paused'
      })
    });
    music.onError((res) => {
      console.log(res.errMsg)
      console.log(res.errCode)
    })

  },
  playOrpause: function() {
    // var that =this;
    if (this.data.playStatus) {
      this.data.music.pause();
      // console.log(this.data.playStatus);


    } else {
      // console.log(this.data.playStatus);
      this.data.music.play();
    }
  },
  onLoad: async function (options) {
    // console.log(options.title);
    // const url = `/song/detail?ids=${options.id}`;
    const url = `/song/url?id=${options.id}`;
    const res = await requestUrl.get(url);
    const res_songDetail= await requestUrl.get(songDetail);
    // const palyMusicUrl = res.data.data[0].url;
    //  console.log(res_lyric.data.lrc.lyric);
    //  console.log(res_songDetail.data.songs);
    this.setData({
      palyMusicUrl: res.data.data[0].url,
      playTitle: options.title,
      songDetail: res_songDetail.data.songs[0]
    });
    
     this.playMusic();
     this.dealLrc();
     
    // console.log(res.data);
    // this.time();
  },
 
musicplay.js
text {
    padding: 0;
    margin: 0;
  }
  .m-song-wrap {
    padding-top: 63px;
}
.m-song-disc {
    position: relative;
    width: 248px;
    height: 248px;
    margin: 0 auto;
}
.m-song-turn {
    width: 100%;
    height: 100%;
}
.m-song-turn:before {
    content: " ";
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    z-index: 2;
    background: url(//s3.music.126.net/mobile-new/img/disc.png?d3bdd10…=) no-repeat;
    background-size: contain;
}
.m-song-rollwrap {
    position: absolute;
    width: 150px;
    height: 150px;
    left: 50%;
    top: 50%;
    z-index: 1;
    margin: -75px 0 0 -75px;
}
.m-song-img {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    overflow: hidden;
    background: url(//s3.music.126.net/mobile-new/img/disc_default.png?ba7c53e…=) no-repeat;
    background-size: contain;
}
.m-song-lgour, .m-song-light {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    z-index: 3;
}
.m-song-light {
    background: url(//s3.music.126.net/mobile-new/img/disc_light.png?2bb24f3…=) no-repeat;
    background-size: contain;
}
.m-song-plybtn {
    position: absolute;
    width: 50px;
    height: 50px;
    left: 50%;
    top: 50%;
    -webkit-transform: translate(-50%,-50%);
    -ms-transform: translate(-50%,-50%);
    transform: translate(-50%,-50%);
    z-index: 10;
    background: url(//s3.music.126.net/mobile-new/img/play_btn_3x.png?4da7e135b7c089f3777ec5cdbbb3a8d8=) 0 0 no-repeat;
    background-size: contain;
}
.m-song-plybtn:after {
    content: "";
    display: block;
    position: absolute;
}
.m-song-disc:after {
    width: 96px;
    height: 137px;
    top: -70px;
    left: 133px;
    background-image: url(//s3.music.126.net/mobile-new/img/needle-ip6.png?be4ebbe…=);
}
.m-song-disc:after {
    content: " ";
    position: absolute;
    top: -63px;
    left: 107px;
    z-index: 5;
    width: 84px;
    height: 122px;
    background: url(//s3.music.126.net/mobile-new/img/needle.png?702cf6d…=) no-repeat;
    background-size: contain;
}
.m-song-light {
    background: url(//s3.music.126.net/mobile-new/img/disc_light.png?2bb24f3…=) no-repeat;
    background-size: contain;
}
.m-song-bg {
    background-color: #161824;
    background-position: 50%;
    background-repeat: no-repeat;
    background-size: 150% 150%;
    -webkit-transform: scale(1.5);
    -ms-transform: scale(1.5);
    transform: scale(1.5);
    -webkit-transform-origin: center;
    -ms-transform-origin: center;
    transform-origin: center;
    position: fixed;
    left: 0;
    right: 0;
    top: 0;
    height: 100%;
    overflow: hidden;
    z-index: 1;
    
}
.m-song-bg:before {
    content: " ";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    top: 0;
    background-color: rgba(0,0,0,.7);
}
.m-song-clickarea {
    position: absolute;
    width: 100%;
    top: 0;
    left: 0;
    bottom: 200px;
    z-index: 10;
    margin-bottom: env(safe-area-inset-bottom);
}
.u-img {
    width: 100%;
    vertical-align: middle;
}
.aboutsougou {
    display: none;
}
.m-song-info {
    padding: 0 35px;
    margin-top: 25px;
    position: relative;
    z-index: 20;
    text-align: center;
}
.m-song-h2 {
    font-size: 18px;
}
.m-song-h2 {
    text-align: center;
    line-height: 1.1;
    color: #fefefe;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
.m-song-autr, .m-song-pure {
    font-size: 16px;
}
.m-song-autr {
    color: hsla(0,0%,100%,.6);
}
.m-song-lrc {
    position: relative;
    margin-top: 14px;
}
.m-song-scroll {
    line-height: 1.5;
    font-size: 13px;
    /* height: 50px; */
    overflow: hidden;
    -webkit-mask: -webkit-linear-gradient(top,#000,#000 70%,rgba(0,0,0,0));
}
.m-song-lremp, .m-song-scroll {
    text-align: center;
    color: hsla(0,0%,100%,.6);
}
.m-song-lritem {
    /* display: inline-flex; */
    height: 32px;
    line-height: 32px;
    
}
/* animation css  */
.a-circling {
    -webkit-animation: circling 20s linear infinite;
    animation: circling 20s linear infinite;
}
.pause{
    animation-play-state:paused;
}
@keyframes circling {
    from {transform: rotateZ(0deg);}
    to {transform: rotateZ(360deg);}
}

@-webkit-keyframes circling {
    from {-webkit-transform: rotate(0deg);
    }
    to {-webkit-transform: rotate(360deg);}
}
.m-song-iner {
    -webkit-transition: -webkit-transform .5s ease-out;
    transition: -webkit-transform .5s ease-out;
    transition: transform .5s ease-out;
    transition: transform .5s ease-out,-webkit-transform .3s ease-out;
}
/*进度条长度  */
.slid{
    display: flex;
    position: relative;
    z-index: 10;
    justify-content: space-between;
    padding: 50rpx 20rpx;
  }
  .slid view{
    
    font-size: 32rpx;
    color: #999;
  }
  slider{
    width: 500rpx;
    margin: 0 20rpx;
    border-radius:5rpx;
    
  }
musicplay.wxss

唱片旋转的效果使用CSS3动画。唱片随歌曲播放和暂停。

<view class="m-song-light a-circling" style="animation-play-state:{{state}}">

 

 

 设定state的状态,‘ ’或者‘pause’

music.onPlay(() => {
      that.setData({
        playStatus: true,
        state: ' '
      })
      this.setCurrentIndex();
    });
    music.onPause(() => {
      console.log('pause');
      that.setData({
        playStatus: false,
        state: 'paused'
      })
    });

2. 播放slide采用了微信小程序的表单组件silder

<view class="slid">
    <view>
        <text class='times'>{{currentTime}}</text>
    </view>
    <slider bindchange="sliderChange" activeColor="#d33a31" block-size="12" backgroundColor="#999" value="{{percent}}" >
    </slider>
    <view>
        <text class='times'>{{duration}}</text> 
    </view>
</view>

获取数据:currentTime duration

处理数据:percent

data: {
    currentTime:'00:00',
    duration:' ',
    percent:' ',
  }
formatTime: function(time) {
     var minute =Math.ceil(time/60)%60;
     var sec = Math.ceil(time)%60;
     return (minute<10? '0'+minute : minute) + ':' + (sec<10 ? '0' +sec : sec)
  },
music.onTimeUpdate(() =>{
      let duration = that.formatTime(music.duration);
      let currentTime = that.formatTime(music.currentTime);
      let percent =(music.currentTime/music.duration*100).toFixed(2);
      // console.log(music.duration +'--'+ percent +'--'+ music.currentTime);
      that.setData({
        duration:duration,
        currentTime: currentTime,
        percent:percent,
        musicTime:parseInt(music.currentTime)
      });
    });

//滑块滑动jS
sliderChange: function(e) { 
    var that=this;
    // that.data.music.pause();
 
    let slideValue = e.detail.value;
    let  seeKPosition = that.data.music.duration/100*slideValue
     that.data.music.seek(seeKPosition);
    // console.log(currentTime)
     setTimeout(function () {
       that.data.music.play();
       }, 500);   
  },
 

获取歌词并设定歌词滚动

//歌词处理,得到的歌词需要经过处理才能使用
dealLrc: function(lrc) {
    // let lrc = this.data.musicLyric;
    var that=this;
    var arr = lrc.split("\n");
    var timeArr = [], lrcArr = [];
    arr.forEach(function (item, index) {
      var time = item.slice(item.indexOf("["), item.indexOf("]") + 1);
      time = that.dealLrcTime(time);
      timeArr.push(time);
      var lrc = item.substr(item.indexOf("]") + 1)+"\n";
      lrcArr.push(lrc);
      // console.log(time)
    });
    // console.log(lrcArr)
    // console.log(timeArr)
    that.setData({
      lyrics: lrcArr,
      lyricsTime:timeArr
    });
  },
  dealLrcTime: function(time) {
    time = time.replace("[", "");
    time = time.replace("]", "");
    var arr = time.split(":");
    var relTime = parseInt(arr[0]) * 60 + parseInt(arr[1]);
    return relTime;
  },
  //找到当前播放时间
  findCurrentIndex(curTime,timeArr) {
    // var curTime = this.data.musicTime;
    // var timeArr = this.data.lyricsTime;
    var index = -1;
    for (let i = 0; i < timeArr.length; ++i) {
      if (timeArr[i] == NaN) {
        continue;
      }
      if (curTime <= timeArr[i]) {
        index = i;
        break;
      }
    }
    return index;
    
  },
//设置当前歌曲播放的位置
  setCurrentIndex:function(){
    var timeId=wx.getStorageSync("timeId");
    if(timeId){
      clearInterval(timeId);
    }
    if(this.data.musicLyric){
      // var audio = this.data.audio;
      // var duration = audio.duration;
      var timeArr = this.data.lyricsTime;
      var currentTime = -1;
      var that = this;
      timeId = setInterval(() => {
        currentTime = that.data.musicTime;
        var currentIndex =that.findCurrentIndex(currentTime, timeArr);
       this.setData({
          currentIndex: currentIndex
        });

      }, 2000);
      wx.setStorageSync("timeId", timeId);
    }
    
  },

onLoad: async function (options) {
    // console.log(options.title);
    // const url = `/song/detail?ids=${options.id}`;
    var that=this;
    const url = `/song/url?id=${options.id}`;
    const lyric=`/lyric/?id=${options.id}`;
    const songDetail=`/song/detail?ids=${options.id}`;
    const res = await requestUrl.get(url);
    const res_lyric= await requestUrl.get(lyric);
    const res_songDetail= await requestUrl.get(songDetail);
    const musicLyric = that.dealLrc(res_lyric.data.lrc.lyric);
    // const palyMusicUrl = res.data.data[0].url;
    //  console.log(res_lyric.data.lrc.lyric);
    //  console.log(res_songDetail.data.songs);
    this.setData({
      palyMusicUrl: res.data.data[0].url,
      playTitle: options.title,
      // musicLyric: res_lyric.data.lrc.lyric,
      songDetail: res_songDetail.data.songs[0]
    });
    
     this.playMusic();
    //  this.dealLrc();
     
    // console.log(res.data);
    // this.time();
  },
                <view>
                    <view style="position:relative">
                        <view class="m-song-info">
                            <h2 class="m-song-h2">
                                <text class="m-song-sname">{{songDetail.name}}</text>
                                <text class="m-song-gap">-</text>
                                <b class="m-song-autr">{{songDetail.ar[0].name}}</b>
                            </h2>
                            <view class="m-song-lrc f-pr">
                                <view class="m-song-scroll" >
                                    <view class="m-song-iner"  style="transform: translateY(-{{32*currentIndex}}px);">
                                        <block wx:for="{{lyrics}}" wx:key="index" wx:for-index="i" >
                                            <view class="m-song-lritem j-lritem" style='{{i==currentIndex?"color: rgb(255, 255, 255);":" "}}'>
                                                {{item}}
                                            </view>
                                        </block>
                                    </view>
                                </view>
                            </view>
                        </view>
                    </view>
                    <view class="m-link m-music-street" style="margin-top: 15px;">
                        <view class="m-musicStreetWakeUp">
                            <image src=""></image>
                        </view>
                    </view>
                </view>

歌词滚动,获取当前所在的歌词位置,CSS控制歌词向上滚动

 

posted @ 2021-05-18 16:24  cheryshi  阅读(833)  评论(0编辑  收藏  举报