Vue 综合应用 -网页音乐播放器
综合应用 - 悦听player 案例
使用 Vue 框架 + axios + api ,开发一个简易的网页音乐播放器
网易云免费歌曲接口:
-
地址:
https://autumnfish.cn/search
-
方法:
GET
-
参数:
keywords
查询关键字 -
响应:歌曲搜索结果 ( 包含要使用的
歌曲 id
、mvid
) -
-
地址:
https://autumnfish.cn/song/url
-
方法:
GET
-
参数:
id
歌曲id,可以从 api 1 中获取 -
响应:歌曲url地址
-
地址:
https://autumnfish.cn/song/detail
-
方法:
GET
-
参数:
ids
歌曲id,可以从 api 1 中获取 -
响应:歌曲详情 (包括封面信息)
-
地址:
https://autumnfish.cn/comment/hot?type=0
-
方法:
GET
-
参数:
id
(歌曲 id , 地址中的type 固定为 0
) 可以从 api 1 中获取 -
响应:歌曲的热门评论
-
地址:
https://autumnfish.cn/mv/url
-
方法:
GET
-
参数:
id
( mvid , 为 0 表示没有mv) 可以从 api 1 中获取 -
响应:mv 的地址
成品效果
引入 Vue 、 axios
- 这里使用的是本地的 Vue.js,下载地址:https://v1-cn.vuejs.org/guide/installation.html
<!-- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> -->
<script src="../../../dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
静态资源
分析结构
1. 基本容器、实例
html 代码 </>
<div class="wrap">
<!-- 播放器主体区域、容器 -->
<div class="play_wrap" id="player">
<!-- 搜索 todo -->
<!-- 内容 todo -->
<!-- 音乐 todo -->
<!-- MV 视频 todo -->
</div>
</div>
javascript 代码 </>
// 创建 Vue 实例
new Vue({
el:"#player",
data:{},
methods:{}
})
2. 搜索界面
html 代码 </>
- +
@keyup.enter="searchMusic"
enter 键抬起,调用搜索方法 - +
v-model="query"
获取用户输入
<div class="search_bar">
<img src="images/player_title.png" alt="logo" />
<!-- 搜索歌曲 、获取用户输入-->
<input @keyup.enter="searchMusic" type="text" autofocus autocomplete="off" v-model="query" />
</div>
javascript 代码 </>
- +
query
保存用户输入 - +
musicList:[]
保存歌曲列表 - +
searchMusic: function (){}
搜索功能函数
// Vue 实例
new Vue({
el:"#player",
data:{
query:"",
musicList:[]
},
methods:{
// 搜索功能
searchMusic: function ()
{
if (this.query.trim() === "") return;
let self = this;
// 搜索歌曲 返回歌曲数据
axios.get(`https://autumnfish.cn/search?keywords=${this.query}`)
.then(res => self.musicList = res.data.result.songs)
.catch(err => console.error(err))
}
}
})
3. 内容界面
html 代码 </>
<div class="center_con">
<!-- 歌曲列表 todo -->
<!-- 歌曲信息容器 todo -->
<!-- 评论容器 todo -->
</div>
- +
v-for="(item, index) in musicList"
生成歌曲列表结构 - +
@click="playMusic(item.id)"
播放歌曲按钮 - +
{{item.name}}
展示歌曲名称 - +
v-if="item.mvid!=0" @click="playMv(item.mvid)"
显示和隐藏 MV 按钮、播放 MV
html 代码 </>
<!-- 歌曲列表 -->
<div class='song_wrapper'>
<ul class="song_list">
<!-- 生成歌曲列表 -->
<li v-for="(item, index) in musicList">
<!-- 播放按钮、拿到歌曲 id -->
<a href="javascript:;" @click="playMusic(item.id)"></a>
<!-- 拿到歌曲名称 -->
<b>{{item.name}}</b>
<!-- 播放歌曲 MV 按钮、拿到歌曲的 mvid -->
<span v-if="item.mvid!=0" @click="playMv(item.mvid)"><i><i></span>
</li>
</ul>
<img src="images/line.png" class="switch_btn" alt="1">
</div>
javascript 代码 </>
- +
playMusic: function (musicId){}
播放歌曲功能 - +
playMv: function (mvid){}
播放歌曲 MV 功能 - +
musicUrl
保存歌曲 url - +
musicCover
保存歌曲封面 url - +
hotComments: []
保存热门评论数组 - +
mvUrl
保存歌曲MV url - +
isPlaying
音频播放状态 - +
isMask
MV 视频遮罩状态
new Vue({
el:"#player",
data:{
query:"",
musicList:[],
musicUrl:"",
musicCover:"",
hotComments:"",
mvUrl: "",
isPlaying: false,
isMask: false,
},
methods:{
// 搜索
searchMusic: function ()
{
if (this.query.trim() === "") return;
let self = this;
// 搜索歌曲 返回歌曲数据
axios.get(`https://autumnfish.cn/search?keywords=${this.query}`)
.then(res => self.musicList = res.data.result.songs)
.catch(err => console.error(err))
},
// 播放歌曲
playMusic: function (musicId)
{
let self = this;
// 1. 获取歌曲 url
axios.get(`https://autumnfish.cn/song/url?id=${musicId}`)
.then(res => self.musicUrl = res.data.data[0].url)
.catch(err => console.error(err))
// 2. 歌曲详情,获取歌曲封面url
axios.get(`https://autumnfish.cn/song/detail?ids=${musicId}`)
.then(res => self.musicCover = res.data.songs[0].al.picUrl)
.catch(err => console.error(err))
// 3. 获取歌曲评论
axios.get(`https://autumnfish.cn/comment/hot?type=0&id=${musicId}`)
.then(res => self.hotComments = res.data.hotComments)
.catch(err => console.error(err))
},
// 播放MV
playMv: function (mvid)
{
axios.get(`https://autumnfish.cn/mv/url?id=${mvid}`)
.then(res =>
{
// 显示视频遮罩
this.isMask = true;
// 获取 mv url
this.mvUrl = res.data.data.url;
})
.catch(err => console.error(err))
},
}
})
歌曲信息、封面
html 代码</>
- +
:class="{playing:isPlaying}"
绑定 class=“playing” 属性,有没有值取决于 isPlaying - +
:src="musicCover"
歌曲封面
<!-- 拿到播放状态 -->
<div class="player_con" :class="{playing:isPlaying}">
<img src="images/player_bar.png" class="play_bar" />
<img src="images/disc.png" class="disc autoRotate" />
<!-- 拿到歌曲封面的 URL 地址 -->
<img :src="musicCover" class="cover autoRotate" />
</div>
热门、评论容器
- +
v-for="(item, index) in hotComments"
热门评论列表 - +
:src="item.user.avatarUrl"
用户头像 - +
{{item.user.nickname}}
用户昵称 - +
{{item.content}}
评论内容
<div class="comment_wrapper">
<h5 class='title'>热门留言</h5>
<div class='comment_list'>
<!-- 生成热门评论列表 -->
<dl v-for="(item, index) in hotComments">
<dt>
<!-- 拿到用户的头像 URL 地址 -->
<img :src="item.user.avatarUrl" alt="user">
</dt>
<dd class="name">
<!-- 用户昵称 -->
{{item.user.nickname}}
</dd>
<dd class="detail">
<!-- 用户的热门评论内容 -->
{{item.content}}
</dd>
</dl>
</div>
<img src="images/line.png" class="right_line">
</div>
4. 歌曲播放界面
- +
:src="musicUrl"
绑定歌曲 url - +
@play="play"
绑定 audio 播放事件(碟片开始旋转) - +
@pause="pause""
绑定 audio 暂停事件(碟片停止旋转)
html </>
<div class="audio_con">
<!-- 拿到歌曲的 URL 地址、绑定事件 -->
<audio ref='audio' :src="musicUrl" @play="play" @pause="pause" autoplay controls loop class="myaudio"></audio>
</div>
javascript </> (完整)
- +
play: function (){}
音乐开始播放时 - +
pause: function (){}
音乐暂停时 - +
hide: function (){}
隐藏MV视频遮罩
// Vue 实例
new Vue({
el:"#player",
data:{
query:"", // 用户输入,搜索
musicList:[], // 每次搜索返回的歌曲数组
musicUrl:"", // 歌曲的 URL 地址
musicCover:"", // 歌曲的 URL 封面
hotComments:"", // 一个歌曲的热门评论数组
mvUrl: "", // MV 视频的 URL 地址
isPlaying: false, // 音乐播放的状态
isMask: false, // MV 视频的遮罩状态
},
methods:{
// 搜索功能
searchMusic: function ()
{
if (this.query.trim() === "") return;
let self = this;
// 搜索歌曲 => 返回歌曲数据
axios.get(`https://autumnfish.cn/search?keywords=${this.query}`)
.then(res => self.musicList = res.data.result.songs)
.catch(err => console.error(err))
},
// 播放歌曲功能
playMusic: function (musicId)
{
let self = this;
// 1. 获取歌曲 url
axios.get(`https://autumnfish.cn/song/url?id=${musicId}`)
.then(res => self.musicUrl = res.data.data[0].url)
.catch(err => console.error(err))
// 2. 歌曲详情,获取歌曲封面 url
axios.get(`https://autumnfish.cn/song/detail?ids=${musicId}`)
.then(res => self.musicCover = res.data.songs[0].al.picUrl)
.catch(err => console.error(err))
// 3. 热门评论获取
axios.get(`https://autumnfish.cn/comment/hot?type=0&id=${musicId}`)
.then(res => self.hotComments = res.data.hotComments)
.catch(err => console.error(err))
},
// 播放 MV 功能
playMv: function (mvid)
{
axios.get(`https://autumnfish.cn/mv/url?id=${mvid}`)
.then(res =>
{
// 显示视频遮罩
this.isMask = true;
// 获取 mv url
this.mvUrl = res.data.data.url;
})
.catch(err => console.error(err))
.finally(() => document.querySelector("video").play())
},
// 播放
play: function ()
{
this.isPlaying = true;
},
// 暂停
pause: function ()
{
this.isPlaying = false;
},
// 隐藏遮罩
hide: function ()
{
this.isMask = false;
document.querySelector("video").pause();
},
}
})
5. MV 播放界面
- +
v-show="isMask"
显示、隐藏遮罩 - +
:src="mvUrl"
MV 视频 url - +
@click="hide"
点击,隐藏遮罩
html </>
<!-- 拿到 MV 视频遮罩状态,显示和隐藏 MV 界面 -->
<div class="video_con" style="display: none;" v-show="isMask">
<!-- 拿到歌曲 MV 的 URL 地址 -->
<video :src="mvUrl" controls="controls"></video>
<!-- 点击视频外面,隐藏视频遮罩 -->
<div class="mask" @click="hide"></div>
</div>