Bootstrap

微信小程序网易云音乐播放界面

微信小程序网易云

效果图

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

HTML

<view class="box">
	<!-- 毛玻璃 -->
	<view class="bgImage">
		<image src="{{img}}" />
	</view>

	<view class="top">
		<view class="topcen" wx:if="{{showlyric===false}}">
			<image src="{{img}}" class="{{stop===true?'urlpi':'urlpic'}}"></image>
		</view>
	</view>
	<!-- 滑块上面 -->
	<view class="up">
		<view wx:for="{{up}}" wx:key="index" class="topfor">
			<image src="{{item}}" style="width:40rpx;height:40rpx"></image>
		</view>
	</view>
	<!-- 滑块左右的时间 -->
	<view class="timeall">
		<view class="time">
			<view>{{nowtime}}</view>
			<view>{{showTotalTime}}</view>
		</view>
	</view>
	<!-- 滑块 -->
	<slider value="{{value}}" inactive-color="rgb(112, 112, 112)" active-color="red" class="mid" min="0" max="{{maxtiem}}" step="1" bindchange="change" bindchanging="changeing" />

	<!-- 下面icon -->
	<view class="down">
		<view wx:for="{{down}}" wx:key="index" class="downfor">

			<!-- 播放/暂停按钮 -->
			<image wx:if="{{index===2 && stop===true}}" src="{{item}}" bindtap="stop" style="width:90rpx;height:90rpx"></image>
			<image wx:if="{{index===2 && stop===false}}" src="../../images/stop.png" bindtap="stop" style="width:90rpx;height:90rpx"></image>

			<!-- 列表循环/单曲循环/随机播放图标 -->
			<image wx:if="{{index===0 && cycle ===0}}" src="../../images/cycle.png" bindtap="random" style="width:45rpx;height:45rpx"></image>
			<image wx:if="{{index===0 && cycle ===1}}" src="../../images/Single_cycle.png" bindtap="random" style="width:45rpx;height:45rpx"></image>
			<image wx:if="{{index===0 && cycle ===2}}" src="{{item}}" bindtap="random" style="width:45rpx;height:45rpx"></image>



			<!-- 其他图标 -->
			<image wx:if="{{index===1}}" src="{{item}}" bindtap="above" style="width:45rpx;height:45rpx"></image>
			<image wx:if="{{index===3}}" src="{{item}}" bindtap="following" style="width:45rpx;height:45rpx"></image>
			<image wx:if="{{index===4}}" src="{{item}}" bindtap="stop" style="width:45rpx;height:45rpx"></image>
		</view>
	</view>
	<!-- 歌词 -->
	<view class="bom" bindtap="showlyric">
		<view catchlongtap="lyr">
			<scroll-view scroll-y="true" class="{{showlyric===true?'display':'none'}}" style="height:600rpx;" scroll-with-animation scroll-top="{{location*30}}" wx:if="{{showlyric===true}}" scroll-top="{{location*32}}" bindscroll="scroll" bindtouchstart="start" bindtouchend="end">
				<view style="height:284rpx"></view>
				<view wx:for="{{lyric}}" wx:key="index" class="lyricfor" style="text-align:center;">
					<view class="{{location===index?'red1':''}}">{{item}}</view>
				</view>
				<view style="height:300rpx"></view>
			</scroll-view>
		</view>
	</view>
	<!-- 歌名,歌手 -->
	<view class="song">
		<view style="margin-top:20rpx">{{songname}}</view>
		<view class="singer">
			<view wx:for="{{singer}}" wx:key="index" style="margin-left:20rpx">{{item.name}}</view>
		</view>
	</view>

	<!-- 滚动水平线 -->
	<view class="center" wx:if='{{isScroll===true}}'>
		<view class="center1">
			<view>{{lyrictimeshow}}</view>
			<view bindtap="goto">播放</view>
		</view>
	</view>
</view>

JS

import dayjs from '../../lib/dayjs.min.js'
import api from "../../http/api"
let bg = wx.getBackgroundAudioManager() //全局变量
let lineTimeId = '';//水平线定时器
let isDelete = false;//是否删除开启的定时器
Page({

  /**
   * 页面的初始数据
   */
  data: {
    cycle: 0, //控制(列表循环0)(单曲循环1)(随机2)
    stop: false, //暂停开始判断条件
    show: true, //定时器判断
    showTotalTime: "00:00",//总时长
    value: 0, //滑块绑定的值
    nowtime: '00:00',//当前播放的时长
    maxtiem: 0,//最大时长
    id: '',  //发请求用的id
    isScroll: false, //是否显示滚动水平线
    songname: '', //歌名
    singer: [],  //演唱者
    lyric: [],//歌词
    lyrictime: [],//歌词时间
    lyrictimeshow: '00:00',//横线指示的时间
    location: 0,
    locationValue: 0,//歌词滚动具体位置
    locationTime: 0,//歌词定位时间
    showlyric: false,//是否展示歌词
    url: '',  //用来装发送拿到url的请求
    img: '',  //用来装发送拿到图片的请求
    index: 0,  //用来接受拿到传入index的值
    idplay: [], //用来接收传入的id数组
    up: [
      '../../images/like.png',
      '../../images/download.png',
      '../../images/vip.png',
      '../../images/comments.png',
      '../../images/three.png'],
    down: [
      '../../images/random.png',
      '../../images/On_a.png',
      '../../images/pla.png',
      '../../images/next.png',
      '../../images/playlist.png'],
  },
  //歌词滚动
  scroll(e) {
    if (this.data.showlyric === true) {
      let i = parseInt(e.detail.scrollTop / 32);
      // console.log(e.detail.scrollTop, i, "i")
      this.setData({
        locationTime: this.data.lyric[i],
        lyrictimeshow: dayjs(this.data.lyrictime[i] * 1000).format("mm:ss")
      });
    }
  },
  //开始
  start(e) {
    console.log('开始')
    this.setData({
      isScroll: true,
      show: false
    })
    isDelete = false;
    if (lineTimeId) {
      clearTimeout(lineTimeId);
      lineTimeId = '';
    }
  },
  //歌词拖动点击播放
  goto(e) {
    //把(mm:ss)转化成(ss)
    let a = Number(this.data.lyrictimeshow.split(':')[0] * 60) + Number(this.data.lyrictimeshow.split(':')[1].split('.')[0]);
    //跳转
    console.log(a, "a")
    bg.seek(a)
    this.setData({
      show: true
    })
  },
  //结束
  end(e) {
    console.log('结束')
    isDelete = true;
    if (lineTimeId = !'') {
      lineTimeId = setTimeout(() => {
        if (isDelete === true) {
          this.setData({
            isScroll: false
          });
          lineTimeId = '';
        }
      }, 4000);
    }
    //定时器延时启动
    setTimeout(() => {
      this.setData({
        show: true
      })
    }, 4000)

  },
  //是否展示歌词
  showlyric() {
    if (this.data.showlyric === false) {
      this.data.showlyric = true
      this.setData({
        showlyric: this.data.showlyric
      })
    } else if (this.data.showlyric === true) {
      this.data.showlyric = false
      this.setData({
        showlyric: this.data.showlyric,
        isScroll: false
      })
    }
    console.log(this.data.showlyric)
  },
  //控制播放顺序 列表循环/单曲循环/随机播放
  random() {
    if (this.data.cycle === 0) {
      this.data.cycle = 1
      this.setData({
        cycle: this.data.cycle
      })
    } else if (this.data.cycle === 1) {
      this.data.cycle = 2
      this.setData({
        cycle: this.data.cycle
      })
    } else if (this.data.cycle === 2) {
      this.data.cycle = 0
      this.setData({
        cycle: this.data.cycle
      })
    }
  },
  //定时器
  playmusic() {
    setInterval(() => {
      if (this.data.show === true) {
        this.data.showTotalTime = dayjs(bg.duration * 1000).format('mm:ss')
        this.data.nowtime = dayjs(bg.currentTime * 1000).format('mm:ss')
        this.data.maxtiem = parseInt(bg.duration)  //解析一个字符传并返回一个整数
        this.data.value = parseInt(bg.currentTime)
        this.setData({
          value: this.data.value,
          showTotalTime: this.data.showTotalTime,
          nowtime: this.data.nowtime,
          maxtiem: this.data.maxtiem
        })
        if (this.data.showlyric === true) {
          for (let i = 0; i < this.data.lyric.length; i++) {
            // console.log(this.data.value, this.data.lyrictime[this.data.lyric.length - 1])
            if (this.data.value > this.data.lyrictime[this.data.lyric.length - 1]) {//最后的歌词的时间比较
              this.setData({
                location: this.data.lyric.length - 1,
                lyrictimeshow: dayjs(this.data.lyrictime[this.data.lyric.length - 1] * 1000).format('mm:ss')
              });
              break;
            }
            // console.log(this.data.nowtime, this.data.lyric[i]);
            if (this.data.value >= this.data.lyrictime[i] && this.data.value < this.data.lyrictime[i + 1]) {
              // console.log("歌词滚动");
              this.setData({
                location: i,
                lyrictimeshow: dayjs(this.data.lyrictime[i] * 1000).format('mm:ss')
              });
              break;
            }
          }
        }
        // console.log(this.data.showTotalTime, "总时长mm-ss")
        // console.log(this.data.nowtime, "当前播放的时长mm-ss")
        // console.log(this.data.maxtiem, "最大时长s")
        // console.log(this.data.value, "value s")
      }
    }, 1000)
  },
  //滑动改变后
  change(event) {
    bg.seek(event.detail.value)
    console.log(event.detail.value, "event.detail.value")
    this.data.show = true
    this.setData({
      show: this.data.show
    })
  },

  //滑动中事件
  changeing(event) {
    let a = false
    this.setData({
      show: a,
      nowtime: dayjs(event.detail.value * 1000).format('mm:ss')
    })
  },
  //暂停
  stop() {
    if (this.data.stop === false) {
      bg.pause()
      this.data.stop = true
      this.setData({
        stop: this.data.stop
      })
    } else {
      bg.play()
      this.data.stop = false
      this.setData({
        stop: this.data.stop
      })
    }
  },
  //获取url
  getUrl() {
    if (this.data.id) {
      api.url(
        this.data.id
      ).then(res => {
        if (res.data[0].url) {
          this.data.url = res.data[0].url
          this.setData({
            url: this.data.url
          })
          bg.src = this.data.url
          bg.title = "123"
        } else {
          this.following()
        }

      }).catch(err => {
        console.log(err)
      })
    } else { this.following() }
  },
  //获取图片
  getImg() {
    api.ids(
      this.data.id
    ).then(res => {
      console.log(res.songs[0].al.name)
      console.log(res.songs[0].ar)
      this.data.songname = res.songs[0].al.name
      this.data.singer = res.songs[0].ar
      this.data.img = res.songs[0].al.picUrl
      this.setData({
        img: this.data.img,
        songname: this.data.songname,
        singer: this.data.singer
      })
    }).catch(ree => {
      console.log(ree)
    })
  },
  //获取歌词
  getLyric() {
    api.lyric(
      this.data.id
    ).then(res => {
      let a = res.lrc.lyric.split('\n')
      let ci = [], citime = []
      a.map(item => {
        // 时间
        let time = item.match(new RegExp("\\[[0-9]*:[0-9]*.[0-9]*\\]", "g"))
        if (time) {
          time = time[0].replace("[", '').replace("]", '')
          let it = Number(time.split(':')[0] * 60) + Number(time.split(':')[1].split('.')[0]);
          //毫秒:+Number(time.split(':')[1].split('.')[1]);
          // console.log(time,dayjs(time).format('mm:ss'));
          citime.push(it)
          ci.push(item.replace(new RegExp("\\[[0-9]*:[0-9]*.[0-9]*\\]", "g"), ''))
        }
      })
      //去空
      let a1 = [], a2 = [];
      for (let i = 0; i < ci.length; i++) {
        if (citime[i] && ci[i]) {//当前是否有歌词
          a1.push(citime[i]);
          a2.push(ci[i]);
        }
      }
      this.data.lyrictime = a1
      this.data.lyric = a2
      this.setData({
        lyrictime: this.data.lyrictime,
        lyric: this.data.lyric
      })
      // console.log(this.data.lyrictime, "lyrictime")
      // console.log(this.data.lyric, 'lyric')
      wx.hideLoading()
    }).catch(ree => {
      console.log(ree)
    })
  },
  //上一首歌
  above() {
    this.setData({
      stop: false
    })
    if (this.data.index > 0) {
      this.setData({
        index: this.data.index - 1
      })
      this.above1()
    } else {
      this.setData({
        index: this.data.idplay.length - 1
      })
      this.above1()
    }
  },
  //上一首歌方法
  above1() {
    this.data.id = this.data.idplay[this.data.index]
    this.setData({
      id: this.data.id
    })
    // 发送请求查看该id是否有版权
    api.music(
      this.data.id
    ).then(res => {
      if (res.success === true) {
        this.getImg()
        this.getUrl()
        this.getLyric()
        //当上一首歌曲url地址为null时候继续调用此方法
        if (this.data.url === null) {
          wx.showToast({
            title: "未找到地址,请听上一首",
            icon: 'none',
            duration: 1000//持续的时间
          })
          setTimeout(() => {
            this.above()
          }, 1000)
        }
      }
    }).catch(ree => {
      // 如果没有版权
      wx.showToast({
        title: ree.response.data.message + "请听上一首",
        icon: 'none',
        duration: 1000//持续的时间
      })
      //再次调用次此方法查看上一首
      setTimeout(() => {
        this.above()
      }, 1000)
    })
  },
  //下一首歌
  following() {
    this.setData({
      stop: false
    })
    //判断只有当当前下标不为最后一个时
    if (this.data.index * 1 < this.data.idplay.length - 1) {
      if (this.data.cycle === 0) { this.data.index = this.data.index * 1 + 1 }
      else if (this.data.cycle === 1) { this.data.index = this.data.index }
      else if (this.data.cycle === 2) {
        let num = parseInt(Math.random() * ((this.data.idplay.length - 1) - 0 + 1) + 0)
        this.data.index = num
        console.log(num + 1, '第几首歌')
      }
      this.setData({
        index: this.data.index
      })
      this.data.id = this.data.idplay[this.data.index]
      this.setData({
        id: this.data.id
      })
      //发送请求查看该id是否有版权
      // 如果有
      api.music(
        this.data.id
      ).then(res => {
        console.log(res)
        this.getImg()
        this.getUrl()
        this.getLyric()
        //当拿到的url为空时候
        if (this.data.url === null) {
          wx.showToast({
            title: "未找到地址,请听下一首",
            icon: 'none',
            duration: 1000//持续的时间
          })
          this.following()
        }
      }).catch(ree => {
        // 如果没有有
        wx.showToast({
          title: ree.response.data.message + "请听一首",
          icon: 'none',
          duration: 1000//持续的时间
        })
        //再次调用次此方法查看下一首
        setTimeout(() => {
          this.following()
        }, 1000)

      })

    } else if (this.data.index * 1 === this.data.idplay.length - 1) {
      this.setData({
        index: 0
      })
      console.log(this.data.index, "index")
      this.following()
    }
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    wx.showLoading({
      title: '加载中',
    })
    this.data.index = options.index
    this.data.idplay = options.id.split(",")
    this.setData({
      index: this.data.index,
      idplay: this.data.idplay
    })
    this.data.id = this.data.idplay[this.data.index]
    this.setData({
      id: this.data.id
    })
    console.log(this.data.id, "id")
    this.getImg()
    this.getUrl()
    this.playmusic()
    this.getLyric()


    //监听音乐自然结束
    bg.onEnded(() => {
      //播放下一首  
      this.following()
    })
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})

CSS

.urlpic {
  width: 550rpx;
  height: 550rpx;
  border-radius: 50%;
  animation: rock 20s linear infinite;
  animation-delay: 0s;
  animation-direction: normal;
  animation-play-state: running;
}

.urlpi {
  width: 550rpx;
  height: 550rpx;
  border-radius: 50%;
  animation: rock 20s linear infinite;
  animation-delay: 0s;
  animation-direction: normal;
  animation-play-state: paused;
}

@keyframes rock {
  0% {
    transform: rotate(0deg)
  }
  100% {
    transform: rotate(360deg)
  }
}

.top {
  background-color: rgba(255, 250, 240, 0);
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  top: 150rpx;
}

.topcen {
  width: 580rpx;
  height: 580rpx;
  border-radius: 50%;
  border: 1rpx solid rgb(163, 163, 163);
  display: flex;
  justify-content: center;
  align-items: center;
}

.up {
  width: 100%;
  display: flex;
  align-items: center;
  position: absolute;
  bottom: 400rpx;
}

.down {
  width: 100%;
  display: flex;
  align-items: center;
  position: absolute;
  bottom: 120rpx;
}

.topfor,
.downfor {
  flex: 1;
  display: flex;
  justify-content: center;
  align-items: center;
}

.box {
  width: 100%;
  height: 100vh;
  background-color: rgba(138, 132, 132, 0.479);
}

.play {
  width: 80rpx;
  height: 80rpx;
}

.middle {
  display: flex;
  width: 80%;
}

.mid {
  width: 70%;
  position: absolute;
  bottom: 290rpx;
  color: rgb(112, 112, 112);
  left: 80rpx;
  z-index: 6;

}

.time {
  width: 97%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  color: white;
}

.timeall {
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  bottom: 310rpx;
  position: absolute;
  z-index: 5;
}

.bgImage {
  filter: blur(30px);
  position: absolute;
  height: 100vw;
  width: 100vw;
  z-index: -1;
}

.bgImage>image {
  height: 100vh;
  width: 100vw;
}

.bom {
  position: absolute;
  width: 100%;
  height: 65%;
  z-index: 7;
  top: 20rpx;
  display: flex;
  justify-content: center;
  align-items: center;
}

.alllyric {
  display: flex;
  align-items: center;
  flex-direction: column;
  color: white;
  height: 500rpx;
  font-size: 30rpx;
  margin-top: 200rpx;
}

.lyricfor {
  margin-top: 20rpx;
  width: 550rpx;
  color: white;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 30rpx;
}

.lyr {
  width: 100%;
  height: 60%;
}

.song {
  width: 100%;
  height: 80rpx;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  color: white;
  font-size: 35rpx;

}

.singer {
  display: flex;
  font-size: 28rpx;
}

.red1 {
  color: red;
  height: 70rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 33rpx;

}

.display {
  display: block;
}

.none {
  display: none;
}

.center {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  position: absolute;
  top: 34%;
  border: 1rpx solid gray;
  height: 70rpx;
  z-index: 999;
}

.center1 {
  display: flex;
  justify-content: space-between;
  width: 95%;
  font-size: 30rpx;
}
;