先放个效果图吧
在这里插入图片描述

首先先把主体结构搭好,样式调好,然后再来写播放器的功能。

根据播放器的形状,将其分为头部(搜索栏),中间(歌曲列表,碟片,热评),尾部(播放器栏),html结构如下

<div class="wrap" id="app">
	<!-- 整体播放器部分 -->
	<div class="play_wrap">
		<!-- 头部 -->
		<div class="search_bar">
			<a href="javascript:location.reload();" class="refresh">
				<p class="player_title">音乐播放器</p>
			</a>
			<input type="text">
			<img src="images/zoom.png" class="search" @click="searchMusic" alt="">
		</div>

可以看到头部中是定义了一个a标签,用来点击后刷新页面,然后是标题,最后是一个文本框加搜索光标

<!-- 中间 -->
<div class="center_con">
	<!-- 中间的左边 -->
	<div class="song_wrapper">
		<!-- 歌曲列表 -->
		<ul class="song_list">
			<li><a href="javascript:;"></a><b>你好</b></li>
			<li><a href="javascript:;"></a><b>你好</b><span><i></i></span></li>
		</ul>
		<img src="images/line.png" class="left_line" alt="line">
	</div>
	<!-- 中间的中间 -->
	<div class="player_con">
		<img src="images/player_bar.png" class="play_bar" alt="bar">
		<img src="images/disc.png" class="disc" alt="disc">
		<img src="images/三笠.png" class="cover" alt="cover">
	</div>
	<!-- 中间的右边 -->
	<div class="comment_wrapper">
		<h5 class="title">热门留言</h5>
		<!-- 热评列表 -->
		<div class="comment_list">
			<dl>
				<dt><img src="images/person.png" alt="person"></dt>
				<dd class="name">jack</dd>
				<dd class="detail">hah</dd>
			</dl>
		</div>
		<img src="images/line.png" class="right_line" alt="">
	</div>
</div>

可以看到中间是分为左中右三部分,左边为歌曲列表,先随便写了两个li当模板,方便书写css样式,中间是三张图,右边是热评列表

<!-- 尾部 -->
<div class="audio_con">
	<!-- 音乐播放器 -->
	<audio src="" controls autoplay loop class="myaudio"></audio>
</div>
<div class="video_con" style="display: none;">
	<!-- mv播放器 -->
	<video src="" controls></video>
	<!-- 遮罩层 -->
	<div class="mask"></div>
</div>

而尾部则是由音乐播放器和mv播放器组成,mv播放器默认状态是不显示的,添加一个遮罩层是为了方便关掉mv。

由于css文件过多这里就不写出来了,可以去gitee自取,地址在最后面。

此时的结果应该是这样的
在这里插入图片描述
准备工作就绪,开始书写播放器的功能。总共分为六部分,歌曲搜索,歌曲播放,歌曲封面,歌曲评论,播放动画,播放mv。

先看第一部分歌曲搜索,想要实现的功能是在搜索栏输入歌曲名字或者歌手名字按下回车后,歌曲列表里能出来相应的歌曲。

想要达到该功能,首先是要通过v-on给搜索栏绑定一个回车事件以及搜索光标绑定一个点击事件,然后就需要使用v-model来双向传递数据,同时通过axios来调用接口查询数据,最后就是用v-for来渲染数据。js程序如下

var app = new Vue({
    el: "#app",
    data: {
        query: "",
    },
    methods: {
        searchMusic: function () {
            axios.get("https://autumnfish.cn/search?keywords=" + this.query).then(function (response) {
                console.log(response);
            }, function (err) {})
        }
    }
})

传入一个空字符串query用来表示搜索的内容,然后定义一个searchMusic函数来搜索歌曲,其中调用axios接口,先打印一下看看response是什么,以及想要的歌曲位置在哪里。

在打印之前先在html中通过v-on给搜索栏绑定回车事件,通过v-model双向传递数据,程序如下

<input type="text" @keyup.enter="searchMusic" v-model="query">
<img src="images/zoom.png" @click="searchMusic" class="search" alt="">

打印结果如下
在这里插入图片描述
可以看到输入歌手sia按下回车后,打印出来的歌曲位于data中的result中的songs里面,因此重新书写该函数

searchMusic: function () {
    var that = this;
    axios.get("https://autumnfish.cn/search?keywords=" + this.query).then(function (response) {
        // console.log(response);
        that.musicList = response.data.result.songs;
    }, function (err) {})
}

并且给data中添加一个空数组musicList 用来存放歌曲,最后就是渲染数据,在html文件中找到歌曲列表那一段,添加v-for

<li v-for="item in musicList">
	<a href="javascript:;"></a>
	<b>{{ item.name }}</b>
	<span><i></i></span>
</li>

第一部分歌曲搜索已做完,第二部分是歌曲播放。想要实现的功能是点击该歌曲后能够进行播放。

想要完成该功能首先是点击列表中的歌(v-on),然后调用接口获取歌曲地址,最后是歌曲地址设置,属性设置是通过v-bind来设置,js程序如下

playMusic: function (musicId) {
    axios.get("https://autumnfish.cn/song/url?id=" + musicId).then(function (response) {
        console.log(response);
    }, function (err) {})
}

首先定义一个playMusic函数,为了具体到播放哪首歌,传入一个形参musicId,然后调用axios接口,同样来打印一下response看看歌曲地址放在哪。

打印之前先给歌曲列表中的a标签绑定一个点击事件

<a href="javascript:;" @click="playMusic(item.id)"></a>

打印结果如下
在这里插入图片描述
可以看到歌曲地址即url这个属性是存放在data中的data中的0数组中的url中,所以该函数重新书写

playMusic: function (musicId) {
    var that = this;
    axios.get("https://autumnfish.cn/song/url?id=" + musicId).then(function (response) {
        // console.log(response);
        that.musicUrl = response.data.data[0].url;
    }, function (err) {})
}

并且给data中添加一个空字符串musicUrl 用来存放歌曲地址,最后就是通过v-bind把这个歌曲地址赋给播放器了

<audio :src="musicUrl" controls autoplay loop class="myaudio"></audio>

第二部分歌曲播放也已经完成,第三部分是歌曲封面。想要实现的功能是让播放器在播放音乐的同时,歌曲封面会自动变化成该歌曲的专辑封面。

要完成该功能首先是要调用接口获取歌曲封面的信息,然后通过v-bind赋给封面所在的标签,和歌曲播放部分类似,js程序如下

axios.get("https://autumnfish.cn/song/detail?ids=" + musicId).then(function (response) {
    console.log(response);
}, function (err) {})

由于是在播放歌曲的同时切换歌曲封面,所以该程序还是在playMusic函数中,打印的结果如下
在这里插入图片描述
可以看到封面地址即picUrl是存放在data中的songs中的0数组中的al中的picUrl中,所以重新书写程序

axios.get("https://autumnfish.cn/song/detail?ids=" + musicId).then(function (response) {
    // console.log(response);
    that.coverUrl = response.data.songs[0].al.picUrl;
}, function (err) {})

同时在data中传入一个空字符串coverUrl用来存放封面地址,然后通过v-bind给封面所在标签赋值

<img :src="coverUrl" class="cover" alt="cover">

第三部分歌曲封面也已经获得,第四部分是热门评论。想要实现的功能是在播放歌曲的同时评论列表也出现该首歌曲下面的热评。

想要完成该功能首先是调用接口获取评论信息,然后通过v-for渲染数据,和歌曲搜索部分类似,js程序如下

axios.get("https://autumnfish.cn/comment/hot?type=0&id=" + musicId).then(function (response) {
    console.log(response);
}, function (err) {})

由于是在播放歌曲的同时显示评论,所以该段程序还是在playMusic函数中,打印结果如下
在这里插入图片描述

可以看到评论信息存放在data中的hotComments中,因此程序如下

axios.get("https://autumnfish.cn/comment/hot?type=0&id=" + musicId).then(function (response) {
    // console.log(response);
    that.comments = response.data.hotComments;
}, function (err) {})

然后通过v-for数组渲染数据,找到评论所在的标签

<dl v-for="item in comments">
	<dt><img src="images/person.png" alt="person" :src="item.user.avatarUrl"></dt>
	<dd class="name">{{ item.user.nickname }}</dd>
	<dd class="detail">{{ item.content }}</dd>
</dl>

由于评论者的头像信息是个地址,所以这里通过v-bind来赋值,然后评论者的名字和其评论都可以在上面打印的信息中找到。

第四部分歌曲评论也已经完成,第五部分是播放动画。想要实现的功能是当播放歌曲时,中间的碟片会一直旋转,停止播放时碟片也随之停止。

要想完成该功能其实就是一个对class="player_con"这个类增删类名的过程,播放时是类名player_con A,暂停时是类名player_con。首先是要绑定两个事件,播放play和暂停pause(这两个事件audio标签是自带的),所以只需要定义一个状态就行了,最后就是通过v-bind添加类名。js程序如下

play: function () {
    this.isPlaying = true;
},
pause: function () {
    this.isPlaying = false;
}

同时在data中添加一个isPlaying: false(平时即未播放音乐时布尔值是false)。audio标签如下

<audio :src="musicUrl" @play="play" @pause="pause" controls autoplay loop class="myaudio"></audio>

增删类名的程序如下

<div class="player_con" :class="{playing:isPlaying}">

类名playing是否增加取决于isPlaying的布尔值,当isPlaying为true时,增加playing类,同时配合css中的程序完成播放动画的效果;当isPlaying为false时,就相当于没有任何变化。

第五部分播放动画也已经完成,第六部分是播放mv。想要实现的功能是mv播放按钮的显示(因为不是所有歌曲都有mv),然后点击播放按钮后,mv在一个遮罩层上播放,点击遮罩层mv又会关闭。

想要实现该功能,首先是要通过v-if和mvid来显示播放按钮,然后调用接口获得mv地址,之后是遮罩层的显示和关闭,最后就是通过v-bind把mv地址赋给video。js程序如下

playMv: function (mvId) {
    axios.get("https://autumnfish.cn/mv/url?id=" + mvId).then(function (response) {
         console.log(response);
    }, function (err) {})
}

mvID在第三步获取歌曲封面的接口中可以找到,所以在HTML中直接调用就行,找到歌曲列表中存放播放mv按钮的标签,程序如下

<span><i v-if="item.mvid!=0" @click="playMv(item.mvid)"></i></span>

当mvid不为0即该歌曲有mv时,该播放按钮就显示,同时添加点击事件,传入mvid参数,然后开始打印信息
在这里插入图片描述
可以看到mv地址存放在data中的data中的url中,因此该函数重新书写为

playMv: function (mvId) {
    var that = this;
    axios.get("https://autumnfish.cn/mv/url?id=" + mvId).then(function (response) {
        // console.log(response);
        that.mvUrl = response.data.data.url;
        that.isShowing = true;
    }, function (err) {})
}

同时在data中定义一个isShowing: false,即平时不播放mv。还定义一个空字符串mvUrl,将其用v-bind赋给video标签

<video :src="mvUrl" controls></video>

然后就是书写遮罩层的函数

<div class="mask" @click="hide"></div>
hide: function () {
    this.isShowing = false;
    this.mvUrl = "";
}

由于点击遮罩层后会停止播放mv,所以这里isShowing为false,而且将mvUrl设为空,就不会出现点击遮罩层退出去后mv还播放的情况。同时还为了解决在播放音乐时,点击播放mv后外面的音乐还在播放的情况,这里选择用ref和$refs来操纵dom元素,在audio标签中添加一个ref

<audio :src="musicUrl" @play="play" @pause="pause" ref="audios" controls autoplay loop
                    class="myaudio"></audio>

然后在playMv函数中添加一行程序

playMv: function (mvId) {
    var that = this;
    axios.get("https://autumnfish.cn/mv/url?id=" + mvId).then(function (response) {
        // console.log(response);
        that.mvUrl = response.data.data.url;
        that.isShowing = true;
        that.$refs.audios.pause();
    }, function (err) {})
},

由于methdos中定义的方法内部,可以通过this关键字来直接调用其他的方法,所以这里可以直接调用pause函数从而达到我们的目的。

至此所有功能都已设置完,文件可以去gitee自取

地址:https://gitee.com/azsx582/music-player-.git

Logo

前往低代码交流专区

更多推荐