网易云音乐——歌曲播放器页面

该文章详细介绍了如何使用VantUI组件库和Vue.js来实现网易云音乐歌曲播放器页面的关键功能,包括顶部导航栏、中间歌曲图片的旋转动画、背景图片模糊效果以及进度条的拖动控制。代码示例涵盖了HTML结构、CSS样式和JavaScript逻辑,涉及组件的使用和事件监听。
摘要由CSDN通过智能技术生成

网易云音乐——歌曲播放器页面

git地址

https://gitee.com/chen-haibin799/netease-cloud-music.git

实现步骤

效果图

在这里插入图片描述

1.实现顶部导航栏

这个写基础样式即可

在这里插入图片描述

注意点:

  • 使用vant组件的 van-nav-bar 的默认背景颜色为白色

    这里需要设置为:

    background-color: transparent
    
    <van-nav-bar style="background-color: transparent;position: relative;z-index: 4;height: 50px;color: white">
      <template #left>
        <van-icon @click="$router.back()" name="xiajiantou" size="18" class-prefix="iconfont"/>
      </template>
      <template #title>
        <div style="font-size: 18px;margin-top: 8px;color: white">{{ data.uiElement.mainTitle.title }}</div>
        <div style="font-size: 12px;color: #666">{{ data.resourceExtInfo.artists[0].name }}></div>
      </template>
      <template #right>
        <van-icon name="fenxiang" size="18" class-prefix="iconfont"/>
      </template>
    </van-nav-bar>

2.实现中间图标旋转

<div
      style="display: flex;position: relative;z-index: 3;justify-content: center;align-items: center;padding: 150px 0">
      <div
        style="text-align: center;background-color: #101012;width: 200px;height: 200px;border-radius: 50%;">
        <img :src="data.uiElement.image.imageUrl" :class="musicState==='true'?'img1':'img2'"
             style="width: 140px;height:140px;border-radius: 50%;line-height: 200px;margin-top: 30px">
      </div>
    </div>
.img1 {
  animation: rotateImg 10s linear infinite;
  animation-play-state: running;
}

.img2 {
  animation-play-state: paused;
}

3.实现背景图片模糊

最外层css样式

需要设置在before中,添加filter,background设置inherit
下层子元素的z-index要超过2,并且position为relative

 z-index: 1;
  position: relative;
  width: 100%;
  height: 100%;
  background-repeat: no-repeat;
  background-size: cover;


.musicPlayBack:before {
  content: "";
  width: 100%;
  height: 100%;
  z-index: 2;
  filter: blur(8px);
  position: absolute;
  top: 0;
  left: 0;
  background: inherit;
}

4.进度条

这里采用vant的van-slider来实现

通过组件的v-model来定义其初始值,max来设置最大值,change方法来实现改变拖动进度条

<div style="display: flex;position: relative;z-index: 4;align-items: center">
      <div style="font-size: 22px;">{{ currentTime }}</div>
      <van-slider v-model="audio" @change="onChange" button-size="12px" style="margin-left: 10px"
                  :max="maxTime"></van-slider>
      <div style="font-size: 22px;">{{ endTime }}</div>
    </div>
// 获取结束时间
    musicLength() {
      this.$store.dispatch('changeTotalTime', this.$store.state.playMusics.length)
      this.endTime = this.$store.state.playMusics.totalDivide + ':' + this.$store.state.playMusics.totalSecond
    },
    // 进度条拖动变化
    onChange(value) {
      this.audio = value
      this.$store.state.musicAudio.music.currentTime = value
      // 如果当前为暂停状态
      if (this.musicState === 'false') {
        this.zanting = 'zanting'
        this.$store.state.musicAudio.music.play()
        this.$store.dispatch("changeMusicState", 'true')
      }
    }

详细代码:

<!--
  Copyright (c) chb my copyright message. 2022-2023. All rights reserved.

  -->

<template>
  <div class="musicPlayBack"
       :style="{backgroundImage: 'url(' +data.uiElement.image.imageUrl +')'  }">

    <van-nav-bar style="background-color: transparent;position: relative;z-index: 4;height: 50px;color: white">
      <template #left>
        <van-icon @click="$router.back()" name="xiajiantou" size="18" class-prefix="iconfont"/>
      </template>
      <template #title>
        <div style="font-size: 18px;margin-top: 8px;color: white">{{ data.uiElement.mainTitle.title }}</div>
        <div style="font-size: 12px;color: #666">{{ data.resourceExtInfo.artists[0].name }}></div>
      </template>
      <template #right>
        <van-icon name="fenxiang" size="18" class-prefix="iconfont"/>
      </template>
    </van-nav-bar>
    <!-- 中间图片   -->
    <div
      style="display: flex;position: relative;z-index: 3;justify-content: center;align-items: center;padding: 150px 0">
      <div
        style="text-align: center;background-color: #101012;width: 200px;height: 200px;border-radius: 50%;">
        <img :src="data.uiElement.image.imageUrl" :class="musicState==='true'?'img1':'img2'"
             style="width: 140px;height:140px;border-radius: 50%;line-height: 200px;margin-top: 30px">
      </div>
    </div>

    <div style="color: white;z-index: 4;position: relative;display: flex;justify-content: space-around">
      <div @click="addLike">
        <van-icon v-if="data.resourceExtInfo.songData.album.onSale===false" name="shoucang1" size="22"
                  class-prefix="iconfont"/>
        <van-icon v-else name="daohangshoucangyishoucang" size="22" class-prefix="iconfont" color="#fe373a"/>
      </div>
      <van-icon name="xiazaidaoru" size="28" class-prefix="iconfont"/>
      <van-icon name="heijiaochangpianji" size="28" class-prefix="iconfont"/>
      <van-icon name="comment" size="28" class-prefix="iconfont"/>
      <van-icon name="gengduo-shuxiang" size="28" class-prefix="iconfont"/>
    </div>
    <!--  布进器  -->
    <div style="display: flex;position: relative;z-index: 4;align-items: center">
      <div style="font-size: 22px;">{{ currentTime }}</div>
      <van-slider v-model="audio" @change="onChange" button-size="12px" style="margin-left: 10px"
                  :max="maxTime"></van-slider>
      <div style="font-size: 22px;">{{ endTime }}</div>
    </div>

    <div
      style="color: white;position: relative;z-index: 3;display: flex;margin-top: 22px;justify-content: space-around;align-items: center;">
      <div>
        <van-icon :name="shunxubofang" size="22" class-prefix="iconfont"/>
      </div>
      <van-icon name="shangyishoushangyige" size="28" class-prefix="iconfont"/>
      <van-icon :name="zanting" size="46" @click="startOrStop" class-prefix="iconfont"/>
      <van-icon name="xiayigexiayishou" size="28" class-prefix="iconfont"/>
      <van-icon name="24gl-playlistMusic" size="28" class-prefix="iconfont"/>
    </div>

  </div>
</template>

<script>
import {addLike} from "../api/like";
import {getSongUrl} from "../api/song";

export default {
  name: "musicPlayBack",
  data() {
    return {
      data: {},
      audio: 0,//音频播放的位置和音频的时间
      maxTime: 100,//最大值
      shunxubofang: 'shunxubofang',
      zanting: 'zanting',
      audioUrl: '',
      currentTime: '00:00',
      endTime: '00:00',
    }
  },
  computed: {
    musicState() {
      return this.$store.state.playMusics.state
    }
  },
  created() {
    this.data = JSON.parse(this.$route.query.data)
    this.init()
  },
  methods: {
    // 初始化音乐并开始播放
    init() {
      let self = this
      console.log(this.data)
      getSongUrl(this.data.resourceExtInfo.songPrivilege.id).then(res => {
        this.audioUrl = res.data.data[0].url
        this.$store.dispatch("changeAudio", res.data.data[0].url)
        this.$store.dispatch("changeMusicState", 'true')
        this.$store.state.musicAudio.music.play()
        this.musicLength()
        let music = this.$store.state.musicAudio.music
        // 获取进度条时间
        music.addEventListener('loadedmetadata', () => {
          setInterval(function () {
            let month = Math.floor(music.currentTime / 60) < 10 ? '0' + Math.floor(music.currentTime / 60) : Math.floor(music.currentTime / 60)
            let secomds = Math.floor(music.currentTime % 60 % 60) < 10 ? '0' + Math.floor(music.currentTime % 60 % 60) : Math.floor(music.currentTime % 60 % 60)
            self.currentTime = month + ":" + secomds
            self.audio = music.currentTime
            self.maxTime = music.duration
          }, 1000)
        })
      })

    },
    // 加入喜欢
    addLike() {
      let like = true
      let that = this
      like = this.data.resourceExtInfo.songData.album.onSale === false;
      addLike(this.data.resourceExtInfo.song.id, like).then(res => {
      })
    },
    // 切换播放状态
    startOrStop() {
      if (this.musicState === 'true') {
        // 暂停
        this.$store.state.musicAudio.music.pause()
        this.$store.dispatch("changeMusicState", 'false')
        this.zanting = 'bofang'
      } else {
        this.zanting = 'zanting'
        this.$store.state.musicAudio.music.play()
        this.$store.dispatch("changeMusicState", 'true');
      }
    },
    // 获取结束时间
    musicLength() {
      this.$store.dispatch('changeTotalTime', this.$store.state.playMusics.length)
      this.endTime = this.$store.state.playMusics.totalDivide + ':' + this.$store.state.playMusics.totalSecond
    },
    // 进度条拖动变化
    onChange(value) {
      this.audio = value
      this.$store.state.musicAudio.music.currentTime = value
      // 如果当前为暂停状态
      if (this.musicState === 'false') {
        this.zanting = 'zanting'
        this.$store.state.musicAudio.music.play()
        this.$store.dispatch("changeMusicState", 'true')
      }
    }
  }
}
</script>

<style scoped lang="scss">
.musicPlayBack {
  z-index: 1;
  position: relative;
  width: 100%;
  height: 100%;
  background-repeat: no-repeat;
  background-size: cover;

  .bottomToggle {
    position: fixed;
    height: 60px;
    bottom: 0;
  }
}


.musicPlayBack:before {
  content: "";
  width: 100%;
  height: 100%;
  z-index: 2;
  filter: blur(8px);
  position: absolute;
  top: 0;
  left: 0;
  background: inherit;
}

.img1 {
  animation: rotateImg 10s linear infinite;
  animation-play-state: running;
}

.img2 {
  animation-play-state: paused;
}

.paused {
  animation-play-state: paused;
}

@keyframes rotateImg {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

零晚.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值