1、需求分析
1-在输入框中输入相应关键词搜索,可以搜索到相应歌曲列表。
2-点击歌曲,获取指定歌曲详细信息(包括:歌曲链接+歌曲图片+歌曲评论)并开始播放。
3-点击播放mv,获取相应歌曲的mv,并在mv层播放。
2、使用的API
博主使用的是网易云音乐的接口api:
1-歌曲列表搜索api:https://autumnfish.cn/search?keywords=雪
2-获取歌曲链接api:https://autumnfish.cn/song/url?id=1001232
3-获取歌曲图片api:https://autumnfish.cn/song/detail?ids=1001232
4-获取歌曲评论列表api:https://autumnfish.cn/comment/hot?id=1001232&type=0
5-获取歌曲mvapi:https://autumnfish.cn/mv/url?id=1001232
3、静态播放器界面效果
vue相关代码
<template>
<section class="container">
<!--音乐播放器-->
<section class="musicPlayer">
<!--头部-->
<div class="header">
<!--logo-->
<div class="logo">
<img src="../assets/logo.png" alt=""><h1>网易云音乐</h1>
</div>
<!--搜索框-->
<div class="search">
<input type="text" autocomplete="off" v-model.lazy="query" @keyup.enter="searchMusic" placeholder="搜索想听的歌" />
</div>
</div>
<!--音乐播放器主体部分-->
<div class="music_list">
<!--歌曲列表-->
<div class="music_content">
<ul>
<li v-for="(item,index) in musicList">
<a href="javascript:;" @click.stop @click="playMusic(item.id,index)" class="el-icon-video-play icon-bofang1"></a>
<label @click="playMusic(item.id,index)">{{item.artists[0].name}}-{{item.name}}</label>
<a href="javascript:;" v-if="item.mvid!=0" @click="playMv(item.mvid)" class="el-icon-video-camera-solid icon-MV"> </a>
</li>
</ul>
</div>
<!--歌曲详细信息-->
<div class="music_detail" :class="{playing:isPlayin}">
<!--指针-->
<img src="../assets/cd_tou.png" class="music_zhen" />
<!--光碟-->
<img :src="musicCover" class="music_pan autoRotate" />
</div>
<!--歌曲评论列表-->
<div class="comment_box">
<h1>热门评论</h1>
<p class="title" v-if="hotComments.length<=0">暂时还没有人评论</p>
<div class="comment_content" v-for="item in hotComments">
<div class="userimg">
<img :src="item.user.avatarUrl" />
</div>
<div class="nickname">
<h3>{{item.user.nickname}}</h3>
<div class="comment">
{{item.content}}
</div>
</div>
</div>
</div>
</div>
<!--播放器底部-->
<div class="audiobox">
<audio id="audio" :src="musicUrl" @play="play" @pause="pause" controls autoplay loop></audio>
</div>
<!--视频mv-->
<div class="mv" v-show="isShow">
<video ref='video' :src="mvUrl" width="100%" height="100%" controls="controls"></video>
</div>
<!--遮罩层-->
<div class="mock" @click="hide" v-show="isShow"></div>
</section>
</section>
</template>
css样式代码
<style scoped lang="scss">
* {
margin: 0;
padding: 0;
font-size: 12px;
list-style: none;
outline: none;
.clear {
clear: left;
}
.container{
width: 100%;
.musicPlayer {
width: 1000px;
height: 570px;
margin: 30px auto 0;
background: url("../assets/back.png");
position: relative;
.header {
width: 100%;
height: 50px;
overflow: hidden;
background-image: linear-gradient(to bottom right, #ff282f, #ff6761);
.logo{
float: left;
overflow: hidden;
img{
height: 30px;
height: 30px;
float: left;
display: block;
margin-left: 10px;
margin-top: 10px;
}
h1 {
color: #fff;
font-size: 16px;
height: 50px;
line-height: 50px;
float: left;
}
}
.search {
float: right;
width: 230px;
height: 25px;
margin-top: 12.5px;
background-color: rgba(255, 255, 255, 0.3);
border-radius: 100px;
line-height: 25px;
margin-right: 20px;
color: white;
/*改变input中placeholder的颜色*/
input::-webkit-input-placeholder {
color: white;
}
input::-ms-input-placeholder {
color: white;
}
input {
width: 80%;
border: 0px;
box-sizing: border-box;
background-color: rgba(0, 0, 0, 0);
margin-left: 10px;
font-size: 12px;
color: #fff;
}
}
}
.music_list {
width: 100%;
min-height: 500px;
box-sizing: content-box;
display: flex;
justify-content: space-between;
background-color: rgba(255,255,255,0.8);
.music_content::-webkit-scrollbar {
/*兼容谷歌*/
display: none;
}
.music_content {
width: 250px;
height: 500px;
display: flex;
justify-content: center;
border-right: 2px solid rgba(205, 205, 205, 0.3);
overflow-x: hidden;
scrollbar-width: none;
/*兼容火狐*/
-ms-overflow-style: none;
/*兼容IE*/
ul{
width: 100%;
li:hover{
background: rgba(255,255,255,0.5);
}
li {
width: 100%;
cursor: pointer;
overflow: hidden;
padding: 10px 15px 10px 10px;
box-sizing: border-box;
color: #000;
a.icon-bofang1{
display: block;
float: left;
width: 15px;
cursor: pointer;
height: 15px;
line-height: 15px;
/*background-image: url(../img/bf.jpg);
background-size:100% ;*/
text-decoration: none;
color: red;
font-size: 16px;
}
a.icon-MV{
display: block;
width: 15px;
float: right;
height: 15px;
cursor: pointer;
line-height: 15px;
/*background-image: url(../img/bf.jpg);
background-size:100% ;*/
text-decoration: none;
color: red;
font-size: 12px;
}
label {
float: left;
height: 15px;
width: 184px;
line-height: 15px;
overflow: hidden;
text-align: left;
cursor: pointer;
margin-left: 10px;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
}
}
}
.music_detail.playing .imgb,
.music_detail.playing .music_pan {
animation-play-state: running;
}
.music_detail.playing .music_zhen {
transform: rotate(0deg);
transition: .5s;
}
.music_detail {
width: 500px;
height: 500px;
border-right: 1px solid rgba(205, 205, 205, 0.3);
position: relative;
overflow: hidden;
.music_zhen {
display: block;
position: absolute;
top: -44px;
right: 100px;
z-index: 3;
transform: rotate(-40deg);
transform-origin: 12px 12px;
transition: .5s;
}
.music_pan {
display: block;
width: 300px;
height: 300px;
position: absolute;
top: calc(50% - 150px);
left: calc(50% - 150px);
border-radius: 1000px;
}
.autoRotate {
animation-name: Rotate;
animation-iteration-count: infinite;
animation-play-state: paused;
animation-timing-function: linear;
animation-duration: 10s;
}
}
.comment_box::-webkit-scrollbar {
/*兼容谷歌*/
display: none;
}
.comment_box {
width: 250px;
height: 500px;
overflow-x: hidden;
scrollbar-width: none;
/*兼容火狐*/
-ms-overflow-style: none;
/*兼容IE*/
h1 {
width: 100%;
text-align: center;
margin-top: 20px;
font-size: 16px;
}
.title{
width: 100%;
text-align: center;
color: rgba(171, 171, 171, 0.99);
height: 40px;
line-height: 40px;
}
.comment_content:first-of-type{
border: unset;
}
.comment_content {
width: 100%;
border-top:1px solid rgba(102, 102, 102, 0.07);
overflow: hidden;
padding: 10px;
box-sizing: border-box;
cursor: pointer;
.userimg {
width: 50px;
height: 50px;
float: left;
overflow: hidden;
border-radius: 50px;
}
.nickname {
width: 169px;
margin-left: 10px;
float: left;
overflow: hidden;
h3 {
font-size: 14px;
text-align: left;
margin-bottom: 3px;
}
.comment {
width: 100%;
text-align: left;
}
}
}
img {
width: 100%;
height: 100%;
}
}
}
.audiobox {
width: 100%;
height: 40px;
background-color: aliceblue;
audio {
width: 100%;
height: 100%;
}
}
.mv {
width: 100%;
height: 600px;
position: absolute;
background-color: #000;
top: 0;
left: 0;
z-index: 7;
}
.mock {
width: 1920px;
height: 810px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
background-color: rgba(0, 0, 0, 0.7);
z-index: 5;
video {
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
}
}
}
}
}
@keyframes Rotate {
from {
transform: rotateZ(0);
}
to {
transform: rotateZ(360deg);
}
}
</style>
4、功能分析
searchMusic(){ }——关键词搜索歌曲列表
async searchMusic(){//关键词搜索歌曲列表
const resp = await searchMusic({keywords: this.query})
this.musicList = resp.result.songs
},
playMusic(muiscId,index) { }——根据歌曲id搜素此歌曲详细信息
async playMusic(muiscId,index) {//根据歌曲id搜素此歌曲详细信息
//查询歌曲链接
const resp1 = await getMusic({id: muiscId})
this.musicUrl = resp1.data[0].url
//查询歌曲图片
const resp2 = await getMusicDetail({ids: muiscId})
this.musicCover = resp2.songs[0].al.picUrl;
//查询歌曲评论
const resp3 = await getMusicComment({
id: muiscId,
type: 0
})
this.hotComments = resp3.hotComments;
},
play(){ }——音乐暂停
play(){//音乐暂停
this.isPlayin = true;//光碟停止旋转
},
pause(){ }——音乐暂停
pause(){//音乐暂停
this.isPlayin = false;//光碟停止旋转
},
playMv(mvid){ }——根据歌曲id搜索歌曲mv
async playMv(mvid){//根据歌曲id搜索歌曲mv
const resp = await getMusicMv({id: mvid})
this.mvUrl = resp.data.url;
//mv层展示
this.isShow = true;
},
hide(){ }
hide(){//mv关闭
this.isShow = false;
/*关闭mv*/
this.$refs.video.pause();
},
5、接口文件
编写一个api文件用来处理数据请求,需要注意的是,项目需要配置代理,可以参考博客《vue&vue-cli 3.0项目中遇到的有趣问题 -(二、vue解决跨域问题)》
import axios from "axios"
const searchMusicAPI = "https://autumnfish.cn/search" //搜索歌曲列表接口
const getMusicAPI = "https://autumnfish.cn/song/url" //获取歌曲链接接口
const getMusicDetailAPI = "https://autumnfish.cn/song/detail" //获取歌曲图片接口
const getMusicCommentAPI="https://autumnfish.cn/comment/hot" //获取歌曲评论接口
const getMusicMvAPI="https://autumnfish.cn/mv/url" //获取歌曲mv接口
export async function searchMusic(params) {//搜索歌曲列表
const resp = await axios({
method: "get",
url: searchMusicAPI,
params: params,
});
return resp.data;
}
export async function getMusic(params) {//获取歌曲链接
const resp = await axios({
method: "get",
url: getMusicAPI,
params: params,
});
return resp.data;
}
export async function getMusicDetail(params) {//获取歌曲图片
const resp = await axios({
method: "get",
url: getMusicDetailAPI,
params: params,
});
return resp.data;
}
export async function getMusicComment(params) {//获取歌曲评论
const resp = await axios({
method: "get",
url: getMusicCommentAPI,
params: params,
});
return resp.data;
}
export async function getMusicMv(params) {//获取歌曲mv
const resp = await axios({
method: "get",
url: getMusicMvAPI,
params: params,
});
return resp.data;
}
并在需要使用的地方import {searchMusic,getMusic,getMusicDetail,getMusicComment,getMusicMv} from '../api/music'
引用
6、功能完善
1-页面初始化时执行一次音乐搜索,增加代码
async mounted() {
//初始化歌曲列表
const resp = await searchMusic({keywords: '泠鸢yousa'})
this.musicList = resp.result.songs
}
2-空值搜索会报错,需要做判断处理,增加代码
async searchMusic(){//关键词搜索歌曲列表
if ((this.query).trim()!=="") {//清空收尾空格,注意控制查找会报错,应剔除
}
},
3-点击歌曲,通过判断是不是同一个歌曲来执行是切换播放状态操作还是获取新歌曲操作,注意按钮的改变,增加代码
async playMusic(muiscId,index) {//根据歌曲id搜素此歌曲详细信息
if (muiscId!==this.musicid) {
//当前歌曲切换为播放状态
$(".music_content ul li").eq(index).find(".icon-bofang1").removeClass("el-icon-video-play");
$(".music_content ul li").eq(index).find(".icon-bofang1").addClass("el-icon-video-pause");
$(".music_content ul li").not($(".music_content ul li").eq(index)).find(".icon-bofang1").removeClass("el-icon-video-pause");
$(".music_content ul li").not($(".music_content ul li").eq(index)).find(".icon-bofang1").addClass("el-icon-video-play");
}else {
let audio = document.getElementById("audio")
if (audio.paused) {//判断歌曲播放状态
//暂停则切换为播放
audio.play();
$(".music_content ul li").eq(index).find(".icon-bofang1").removeClass("el-icon-video-play");
$(".music_content ul li").eq(index).find(".icon-bofang1").addClass("el-icon-video-pause");
} else {
//播放则切换为暂停
audio.pause();
$(".music_content ul li").eq(index).find(".icon-bofang1").removeClass("el-icon-video-pause");
$(".music_content ul li").eq(index).find(".icon-bofang1").addClass("el-icon-video-play");
}
}
},
4-切换audio播放状态时,需要伴随着相应歌曲播放按钮的改变,增加代码
play(){//音乐播放
//搜索当前音乐播放位置并切换为播放按钮为播放状态
let index=-1;
for (let i=0;i<this.musicList.length;i++){
if((this.musicList)[i].id===this.musicid){
index=i;
}
}
$(".music_content ul li").eq(index).find(".icon-bofang1").removeClass("el-icon-video-play");
$(".music_content ul li").eq(index).find(".icon-bofang1").addClass("el-icon-video-pause");
},
5-打开或关闭mv,需要伴随着歌曲的暂停或继续,增加代码
let audio = document.getElementById("audio")
//打开mv需要暂停当前音乐
audio.pause();
//关闭mv并继续播放当前音乐
audio.play();
7、完整js代码
<script>
import {searchMusic,getMusic,getMusicDetail,getMusicComment,getMusicMv} from '../api/music'
export default {
name: "MusicPlayer",
async mounted() {
//初始化歌曲列表
const resp = await searchMusic({keywords: '泠鸢yousa'})
this.musicList = resp.result.songs
console.log(this.musicList)
this.musicCover=require("../assets/p.png")
},
data(){
return{
query:"",//搜索框搜索内容
musicList:[],//歌曲列表
musicUrl:"",//歌曲链接
musicCover:"",//歌曲图片
hotComments:[],//歌曲评论
isPlayin:false,//播放器播放状态
isShow:false,//mv层显示状态
mvUrl:"",//歌曲mv链接
musicid:"",//歌曲id
}
},
methods:{
async searchMusic(){//关键词搜索歌曲列表
if ((this.query).trim()!=="") {//清空收尾空格,注意控制查找会报错,应剔除
const resp = await searchMusic({keywords: this.query})
this.musicList = resp.result.songs
//console.log(this.musicList)
//初始化音乐,列表播放按钮状态
//主要防止上一次指定位置歌曲播放,重新搜索之后对应位置还是播放状态
//每次再搜索都是待播放
$(".music_content ul li").find(".icon-bofang1").removeClass("el-icon-video-pause");
$(".music_content ul li").find(".icon-bofang1").addClass("el-icon-video-play");
}
},
async playMusic(muiscId,index) {//根据歌曲id搜素此歌曲详细信息
/*获取歌曲地址*/
//对比本次操作和上次存储的歌曲id决定操作
//如果是同一个歌曲id则,不进行搜索,而是进行播放状态切换操作
//如果不同,则进行歌曲详情搜索,请切换为播放状态
if (muiscId!==this.musicid) {
//如果歌曲id不同,则进行歌曲详情搜索,请切换为播放状态
//查询歌曲链接
const resp1 = await getMusic({id: muiscId})
this.musicUrl = resp1.data[0].url
//console.log(resp1)
//查询歌曲图片
const resp2 = await getMusicDetail({ids: muiscId})
this.musicCover = resp2.songs[0].al.picUrl;
//console.log(resp2)
//查询歌曲评论
const resp3 = await getMusicComment({
id: muiscId,
type: 0
})
this.hotComments = resp3.hotComments;
//console.log(resp3)
this.musicid=muiscId;//存储本次歌曲id,供下一次比较使用
//当前歌曲切换为播放状态
$(".music_content ul li").eq(index).find(".icon-bofang1").removeClass("el-icon-video-play");
$(".music_content ul li").eq(index).find(".icon-bofang1").addClass("el-icon-video-pause");
$(".music_content ul li").not($(".music_content ul li").eq(index)).find(".icon-bofang1").removeClass("el-icon-video-pause");
$(".music_content ul li").not($(".music_content ul li").eq(index)).find(".icon-bofang1").addClass("el-icon-video-play");
}else {
//如果是同一个歌曲id则,不进行搜索,而是进行播放状态切换操作
let audio = document.getElementById("audio")
if (audio.paused) {//判断歌曲播放状态
//暂停则切换为播放
audio.play();
$(".music_content ul li").eq(index).find(".icon-bofang1").removeClass("el-icon-video-play");
$(".music_content ul li").eq(index).find(".icon-bofang1").addClass("el-icon-video-pause");
} else {
//播放则切换为暂停
audio.pause();
$(".music_content ul li").eq(index).find(".icon-bofang1").removeClass("el-icon-video-pause");
$(".music_content ul li").eq(index).find(".icon-bofang1").addClass("el-icon-video-play");
}
}
},
//audio自身
play(){//音乐播放
this.isPlayin = true;//光碟开始旋转
//搜索当前音乐播放位置并切换为播放按钮为播放状态
let index=-1;
for (let i=0;i<this.musicList.length;i++){
if((this.musicList)[i].id===this.musicid){
index=i;
}
}
$(".music_content ul li").eq(index).find(".icon-bofang1").removeClass("el-icon-video-play");
$(".music_content ul li").eq(index).find(".icon-bofang1").addClass("el-icon-video-pause");
},
//audio自身
pause(){//音乐暂停
this.isPlayin = false;//光碟停止旋转
//搜索当前音乐播放位置并切换为播放按钮为暂停状态
let index=-1;
for (let i=0;i<this.musicList.length;i++){
if((this.musicList)[i].id===this.musicid){
index=i;
}
}
$(".music_content ul li").eq(index).find(".icon-bofang1").removeClass("el-icon-video-pause");
$(".music_content ul li").eq(index).find(".icon-bofang1").addClass("el-icon-video-play");
},
async playMv(mvid){//根据歌曲id搜索歌曲mv
//console.groupCollapsed(audio.paused)
const resp = await getMusicMv({id: mvid})
this.mvUrl = resp.data.url;
//mv层展示
this.isShow = true;
//console.log(resp)
//打开mv需要暂停当前音乐
let audio = document.getElementById("audio")
audio.pause();
},
/*隐藏mv*/
hide(){//mv关闭
this.isShow = false;
/*关闭mv*/
let audio = document.getElementById("audio")
this.$refs.video.pause();
//继续播放当前音乐
audio.play();
}
}
}
</script>
8、最终效果
9、参考博客
参考博客https://blog.csdn.net/m0_51408910/article/details/111782427
这是博主在休息的时候制作的简易版网易云音乐播放器,如果大家喜欢请多多支持博主哦~~,谢谢。
——————谢谢——————