在b站看完vue教程的悦听音乐播放器案例,有很大的收获,这里自己总结一下,由于之前不太理解弹性盒子的知识,又去b站看了另一位老师的课,也将其所给的资源下载下来发布在博客中:弹性盒子flex

首先对界面功能进行分析,从上到下是搜索栏、主体部分、音频播放进度条;其中主体部分昨从到右分为音乐播放列表、黑胶碟片的歌曲图片、留言列表。

mv播放:

注意:引入vue和axios的js文件时,需要在最后引入,否则数据渲染不出来

   vue中定义data中的数据的时候记得是数据名:数据!!!!每次都写成等号报错!

 

一、功能总结

  • 歌曲搜索:输入歌曲的相关内容按回车键搜索数据;具体步骤为按下回车-->查询数据-->渲染数据
  • 歌曲播放:点击音乐列表前的红色按键播放音乐;具体步骤为点击按钮-->获取歌曲地址-->歌曲地址绑定(v-bind)
  • 歌曲封面:点击音乐播放后音乐的黑胶封面会变成相应歌曲的封面;具体步骤为点击播放歌曲->获取歌曲封面->歌曲封面绑定
  • 歌曲评论:点击音乐播放按钮后音乐的热评数据会渲染到界面上;具体步骤为点击播放歌曲->歌曲评论获取(接口 歌曲id)->歌曲评论渲染
  • 播放动画:在音乐播放时,黑胶碟片转动,在音乐暂停时,黑胶碟片停止转动;具体步骤为监听音乐播放(v-on play)->监听音乐暂停(v-on pause)->操纵类名
  • mv播放:点击mv播放按钮时,播放音乐的mv,不想看mv时,点击旁边的遮罩层,mv播放界面就会隐藏;具体步骤为mv图标显示(v-if)->mv地址获取(接口 mvid)->遮罩层(v-show v-on)->mv地址设置(v-bind)

 

二、html结构

html结构不算复杂,但是学习到的东西还是挺多的。废话不多说,上代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>悦听</title>
    <link rel="stylesheet" href="css/index.css">
    <script src="js/index.js"></script>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>   <!--引入axios-->
</head>
<body>
    <div class="wrap">
        <!-- 播放器主体区域 -->
        <div class="play_wrap" id="player">

            <!-- 搜索栏 -->
            <div class="search_bar">
                <!--悦听标题图片  -->
                <img src="images/player_title.png" alt="" />
                <!-- 搜索歌曲 -->
                <input type="text" autocomplete="off" />
            </div>

            <!-- 主体部分 -->
            <div class="center_con">
                <!-- 搜索歌曲列表 -->
                <div class='song_wrapper'>
                    <ul class="song_list">
                        <li><a href="javascript:;"></a> <b>你好</b> <!----></li>
                        <li v-for="item in musicList">
                            <a href="javascript:;" @click="musicPlayer(item.id);musicCover(item.id);musicComments(item.id)"></a>  <!--音乐播放按钮-->
                            <b>{{item.name}}</b>   <!--音乐名 -->
                            <span><i>{{item.mvid}}</i></span>   <!--mv播放按钮-->
                        </li>
                    </ul>
                    <!-- 左边分割线图片 -->
                    <img src="images/line.png" class="switch_btn" alt="">
                </div>

                <!-- 歌曲信息容器 -->
                <div class="player_con playing" >
                    <img src="images/player_bar.png" class="play_bar" />
                    <!-- 黑胶碟片图片 -->
                    <img src="images/disc.png" class="disc autoRotate" />
                    <!-- 歌曲封面图片 -->
                    <img src="images/cover.png" class="cover autoRotate" />
                </div>

                <!-- 评论容器 -->
                <div class="comment_wrapper">
                    <h5 class='title'>热门留言</h5>
                    <div class='comment_list'>
                        <ul class="comment">
                            <li  class="comment_li">
                                <div class="comm_up">
                                      <img class="user_pic" src="images/person.png"/>    <!--热评头像-->
                                    <b class="user_nickname"></b><br/>
                                </div>
                              
                                <div class="comm_right">
                                    <span class="detail"></span>
                                </div>
                            </li>
                        </ul>
                    </div>
                     <!-- 右边分割线图片 -->
                    <img src="images/line.png" class="right_line">
                </div>
            </div>

            <!-- 播放进度条部分 -->
            <div class="audio_con">
                <audio src="" class="myaudio" controls autoplay looop></audio>
            </div>

            <!-- 视频mv -->
            <div class="video_con">
                <video src="" controls="control">
                    <div class="mask"> </div>
                </video>
            </div>
        </div>
      </div>
</body>
</html>

 

三、css样式及注解

参考别人的代码,自己边查边学习边写,学习到了css很多之前没学到的东西。

1.css未了解到的内容:

(1).body、p、ul&ol、button、font-size在css中都有默认的设置,具体如下:

  •  body的margin为8px;
  •     webkit默认行高18px;height18px;
  •     默认font-size16px
  •     p默认margin是16px 0 16px 0;
  •     ul和ol有默认的margin-left:40px的padding-left和16px 0 16px 0;
  •     button有2px的border;我没搞懂为什么button之间有空格;

 

(2).position属性:

position规定元素的定位类型,任何元素都可以定位,不过绝对定位固定定位元素会生成一个块级框,而不论该元素本身是什么类型。相对定位元素会相对于它在正常流中的默认位置偏移。

position的默认类型是static,其他具体的position值如下:

描述

absolute

生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位。

元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。

fixed

生成绝对定位的元素,相对于浏览器窗口进行定位。 

元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。

relative

生成相对定位的元素,相对于其正常位置进行定位。

因此,"left:20" 会向元素的 LEFT 位置添加 20 像素。

static

默认值。没有定位,元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index 声明)。

inherit

规定应该从父元素继承 position 属性的值。

 

(3).z-index属性:

  • z-index 属性设置元素的堆叠顺序。拥有更高堆叠顺序的元素总是会处于堆叠顺序较低的元素的前面。
  • z-index可以为负值,z-index=-1,把它理解成一个层叠效果就好了,z-index:-1就是在平面的下面一层。

 

(4).background属性:

  • background 简写属性在一个声明中设置所有的背景属性。
  • 如果不设置其中的某个值,也不会出问题,比如 background:#ff0000 url('smiley.gif'); 也是允许的。通常建议使用这个属性,而不是分别使用单个属性,因为这个属性在较老的浏览器中能够得到更好的支持,而且需要键入的字母也更少。

描述

CSS

background-color

规定要使用的背景颜色。

1

background-position

规定背景图像的位置。

1

background-size

规定背景图片的尺寸。

3

background-repeat

规定如何重复背景图像。

1

background-origin

规定背景图片的定位区域。

3

background-clip

规定背景的绘制区域。

3

background-attachment

规定背景图像是否固定或者随着页面的其余部分滚动。

1

background-image

规定要使用的背景图像。

1

inherit

规定应该从父元素继承 background 属性的设置。

1

具体参考background属性w3c

 

(5).css中容易混淆的类使用方式

  • 在css中,类名+空格+类名,表示一种前后代关系。即.class1  .class2{}
  • 在css中 ,类名+类名,表示一种多类选择器,匹配同时具有这两个类的元素。即.class1.class2{}
  • 在html中,class="类名+空格+类名",表示该元素同时拥有两个类。即<div class="class1 class2"></div>

例:

html代码:

<div class="player_con playing" >
    <img src="images/player_bar.png" class="play_bar" />
    <!-- 黑胶碟片图片 -->
    <img src="images/disc.png" class="disc autoRotate" />
    <!-- 歌曲封面图片 -->
    <img src="images/cover.png" class="cover autoRotate" />
</div>

css代码:

.player_con.playing .disc,.player_con.playing .cover {
  animation-play-state: running;
}

其中.player_con.playing代表同时匹配这两个类;

.player_con.playing  .disc代表player_con.playing下面的disc类是它们的子类;

.player_con.playing  .cover代表player_con.playing下面的cover类是它们的子类;

 

(6).@keyframs:

通过@keyframs可以创建动画,创建动画的原理是,可以逐渐从一套css样式转化为另一套css样式,在动画过程中,能够多次改变这套 CSS 样式。可以通过百分比来规定改变发生的时间,也可以通过关键字"from"和"to",等价于 0% 和 100%;其中0%是动画开始的时间,100%是动画结束的时间。

语法为:@keyframs 动画名称 {动画的选择器:{样式}}

@keyframes mymove
{
0%   {top:0px;}
25%  {top:200px;}
50%  {top:100px;}
75%  {top:200px;}
100% {top:0px;}
}

 

(7).transform属性:

其作用是旋转div,transform元素可以应用于2D和3D的场景,可以实现元素的旋转、倾斜、移动、缩放功能。具体的transform值参考:菜鸟教程transform使用教程

一个旋转的例子:

@keyframes Rotate {   /*使 div 元素匀速向下移动:*/
    from {
      transform: rotateZ(0);   /*规定旋转的角度*/
    }
    to {
      transform: rotateZ(360deg);
    }
}

 

(8).为一个标签设置旋转属性,包括调用以上两个属性transform和@keyframs

html代码:

<!-- 黑胶碟片图片 -->
<img src="images/disc.png" class="disc autoRotate" />
<!-- 歌曲封面图片 -->
<img src="images/cover.png" class="cover autoRotate" />

css代码:

.autoRotate {
    animation-name: Rotate;   /*为 @keyframes 动画规定一个名称*/
    animation-iteration-count: infinite;  /*animation-iteration-count 属性定义动画的播放次数。这里是无限次播放*/
    animation-play-state: paused;   /*animation-play-state 属性规定动画正在运行还是暂停。*/
    animation-timing-function: linear;  /*规定动画的速度曲线。速度曲线定义动画从一套 CSS 样式变为另一套所用的时间。速度曲线用于使变化更为平滑。*/
    animation-duration: 5s;   /*animation-duration 属性定义动画完成一个周期所需要的时间,以秒或毫秒计。*/
}
  •  animation-name: Rotate;  ->为 @keyframes 动画规定一个名称;具体查看animation-name具体介绍
  •  animation-iteration-count: infinite;   ->animation-iteration-count 属性定义动画的播放次数。这里是无限次播放;具体查看animation-iteration-count具体介绍
  •  animation-play-state: paused;  ->  animation-play-state 属性规定动画正在运行还是暂停。具体查看 animation-play-state具体介绍
  •  animation-timing-function: linear;   ->规定动画的速度曲线。速度曲线定义动画从一套 CSS 样式变为另一套所用的时间。速度曲线用于使变化更为平滑。具体查看 animation-timing-function具体介绍
  •  animation-duration: 5s;   -> animation-duration 属性定义动画完成一个周期所需要的时间,以秒或毫秒计。具体查看animation-duration具体介绍

 

(9).transition

transition 属性是一个简写属性,用于设置四个过渡属性:

  • transition-property
  • transition-duration
  • transition-timing-function
  • transition-delay

具体请看w3c教程transition具体教程

 

2.css代码

body,   /*这些必须要设置,不然设置songlist的时候li左边会有边距*/
ul,
li{
  margin: 0px;
  padding: 0px;
}
/* 大背景 */
.wrap{
    position: fixed;
    /*  CSS 中 left 是规定元素左边缘的属性, 
    该属性定义了定位元素左外边距边界与其包含块左边界之间的偏移.
     left 也可以作为 float 属性的属性值, 表示元素向左浮动.*/
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background: url("../images/bg.jpg") no-repeat;
    background-size: 100% 100%;
}

/* 悦听音乐的整体轮廓 */
.play_wrap{
    width: 800px;
    height: 544px;
    position: fixed; 
    top: 50%;
    left: 50%;
    margin-left: -400px;
    margin-top: -272px;
    /* background-color: blue; */
}


/* 搜索栏 */
.search_bar{
    height: 60px;
    background-color: #1eacda;
    border-top-left-radius: 4px;   /*设置左上边框弧度*/
    border-top-right-radius: 4px;
    /*弹性盒子布局以下3句  */
    display: flex;
    align-items: center;   /*垂直居中对齐  */
    justify-content: space-between;   /*水平对齐,并且盒子内的所有item之间都有保留空白 */
   
    position: relative;  
    z-index: 11;   /*z-index 属性设置元素的堆叠顺序。拥有更高堆叠顺序的元素总是会处于堆叠顺序较低的元素的前面。*/
}

.search_bar img{   /*标题img*/
    margin-left: 23px;
}

.search_bar input{
    margin-right: 23px;
    width: 296px;
    height: 34px;
    border-radius: 17px;
    border: 0px;
    background: url("../images/zoom.png")  265px  no-repeat rgba(255, 255, 255, 0.45);   /* backgound的设置依次为背景图url、margin-left、图片不重复、背景颜色 */
    text-indent: 15px;  /*将段落的第一行缩进*/
    outline: none;  /*outline (轮廓)是绘制于元素周围的一条线,位于边框边缘的外围,可起到突出元素的作用。zheli outline:none*/

}


/* 主体内容 */
.center_con {
    height: 435px;
    background-color: rgba(255, 255, 255, 0.5);
    display: flex;
    position: relative;
}

/* 歌曲列表 */
.song_wrapper{
    width: 200px;
    height: 435px;
    /* box-sizing: border-box;   规定两个并排的带边框的框 */
    padding: 10px;
    list-style: none;
    position: absolute;
    left: 0px;
    top: 0px;
    z-index: 1;
    /* background-color: brown; */
}

.song_list{
    width: 200px;
    height: 100%;
    overflow-y: auto;
    overflow-x: hidden;
    /* background-color: chocolate; */
}

.song_list::-webkit-scrollbar{    /*滚动条消失,但是可以翻动页面*/
    display: none;
}

.song_list li{ 
    width: 100%;
    height: 40px;
    padding-left: 10px;
    font-size: 12px;
    color: #333;
    margin-bottom: 10px;
    display: flex;
    align-items: center;   /*垂直居中*/
    flex-wrap: wrap;   /*弹性盒子布局,子项目一行装不下,会正序多行显示*/
    /* background-color: blueviolet; */

}

.song_list li:nth-child(odd) {/*规定属于其父元素的第奇数个元素的背景色;odd为奇数,even为偶数,这里的括号中也可以传入具体的数字*/
    background-color: rgba(240, 240, 240, 0.3);
} 

.song_list li a{  /*播放的按钮图片*/
    width: 17px;
    height: 17px;
    display: block;
    background-image: url("../images/play.png");
    background-size: 100%;
    margin-right: 5px;
}

.song_list li b{   /*歌名*/
    width: 122px;
    font-weight: normal;
    /* 以下三行是实现单行文本溢出显示为省略号 */
    overflow: hidden;   
    text-overflow: ellipsis;  /*单行文本溢出显示省略号*/
    white-space: nowrap;
    float: left;
    /* background-color: darkcyan; */
}

/* 为显示mv播放按钮预留空间 */
.song_list li span {
    width: 23px;
    height: 17px;
    padding-left: 20px;
}

/* mv视频播放按钮图片样式 */
.song_list li span i {
    display: block;
    /* width: 100%; */
    height: 100%;
    cursor: pointer;
    background-color: blue;
    /* background: url("../images/table.png");
    background-repeat: no-repeat; */
    background: url("../images/table.png") left -48px no-repeat;
  }


/*歌曲信息,即黑胶碟片 */
.player_con{
    width: 400px;
    height: 435px;
    position: absolute;
    left: 200px;
    top: 0px;
}

.disc{
    position: absolute;
    left: 73px;
    top: 60px;
    z-index: 9;   /*z-index值大会在上层*/
}

.cover{
    position: absolute;
    left: 125px;
    top: 112px;
    width: 150px;
    height: 150px;
    border-radius: 75px;    /*将图片变成圆形*/
    z-index: 8;
}


/* 评论容器 */
.comment_wrapper{
    width: 180px;
    height: 435px;
    list-style: none;
    position: absolute;
    left: 600px;
    top: 0px;
    padding: 25px 10px;
}

.title {  /*.类名 空格 .类名表示一种前后代关系*/
    position: absolute;
    top: 0;
    /* margin-top: 10px;
    margin-bottom: 10px; */
}

.comm_up{
    margin-top: 20px;
}

.comment_list{
	height: 415px;
	overflow-y: auto;
  	overflow-x: hidden;
}
.user_pic{
	width: 40px;
	height: 40px;
	border-radius: 50%;
}
.comm_right{
	margin: 10px;
}
.user_comm{  /*评论内容细节样式*/
	font-size: 12px;
	color: #666;
}

.comment_list::-webkit-scrollbar{    /*滚动条消失,但是可以翻动页面*/
    display: none;
}

.user_nickname{
    padding-top: -30px;
    font-size: 12px;
}



/* 旋转的动画 */
@keyframes Rotate {   /*使 div 元素匀速向下移动:*/
    from {
      transform: rotateZ(0);   /*规定旋转的角度*/
    }
    to {
      transform: rotateZ(360deg);
    }
}

/* 旋转的类名 */
.autoRotate {
    animation-name: Rotate;   /*为 @keyframes 动画规定一个名称*/
    animation-iteration-count: infinite;  /*animation-iteration-count 属性定义动画的播放次数。这里是无限次播放*/
    animation-play-state: paused;   /*animation-play-state 属性规定动画正在运行还是暂停。*/
    animation-timing-function: linear;  /*规定动画的速度曲线。速度曲线定义动画从一套 CSS 样式变为另一套所用的时间。速度曲线用于使变化更为平滑。*/
    animation-duration: 5s;   /*animation-duration 属性定义动画完成一个周期所需要的时间,以秒或毫秒计。*/
}

.player_con.playing .disc,.player_con.playing .cover {
  animation-play-state: running;  /* /*animation-play-state 属性规定动画正在运行还是暂停。*/
}

.play_bar {
    position: absolute;
    left: 200px;
    top: -10px;
    z-index: 10;
    transform: rotate(-25deg);  /* 播放杆 转到播放位置 */
    transform-origin: 12px 12px;  /*transform-origin 属性允许您改变被转换元素的位置。*/
    transition: 1s;   /* transition是四个transition子项的缩写*/
}

/* 播放杆 转回去 */
.player_con.playing .play_bar {
    transform: rotate(0);
}

/*左右分割线样式*/
.switch_btn {
    position: absolute;
    right: 0;
    top: 0;
    cursor: pointer;
}
  .right_line {
    position: absolute;
    left: 0;
    top: 0;
}


/* 播放进度条部分样式 */
.audio_con{
    height: 50px;
    background-color: #f1f3f4;
    border-bottom-left-radius: 4px;
    border-bottom-right-radius: 4px; 
}

.myaudio{
    width: 800px;
    height: 40px;
    margin-top: 5px;
    outline: none;  /*outline (轮廓)是绘制于元素周围的一条线,位于边框边缘的外围,可起到突出元素的作用。*/
    background-color: #f1f3f4;
}

/* mv播放部分样式 */
.video_con video {
    position: fixed;
    width: 800px;
    height: 546px;
    left: 50%;
    top: 50%;
    margin-top: -273px;
    transform: translateX(-50%);  /*向X轴逆向平移50%*/
    z-index: 990;
}
.mask {
    position: fixed;
    width: 100%;
    height: 600px;
    left: 0;
    top: 0;
    z-index: 980;
    background-color: rgba(0, 0, 0, 0.8);
}







 

三、vue代码实现

接口设计:

1.歌曲搜索接口
    请求地址:https://autumnfish.cn/search
    请求方法:get
    请求参数:keywords(查询关键字)
    响应内容:歌曲搜索结果
2.歌曲url获取接口
    请求地址:https://autumnfish.cn/song/url
    请求方法:get
    请求参数:id(歌曲id)
    响应内容:歌曲url地址
3.歌曲详情获取
    请求地址:https://autumnfish.cn/song/detail
    请求方法:get
    请求参数:ids(歌曲id)
    响应内容:歌曲详情(包括封面信息)
4.热门评论获取
       请求地址:https://autumnfish.cn/comment/hot?type=0
    请求方法:get
    请求参数:id(歌曲id,地址中的type固定为0)
    响应内容:歌曲的热门评论
5.mv地址获取
    请求地址:https://autumnfish.cn/mv/url
    请求方法:get
    请求参数:id(mvid,为0表示没有mv)
    响应内容:mv的地址
 

js代码:

var app=new Vue({
    el:"#player",
    data:{
        query:"",   //存储搜索框中搜索数据
        musicList:[],   //保存歌曲信息数组
        musicurl:"",   //获取歌曲的url
        musiccover:"",   //歌曲的封面
        musichotcomments:[],  //歌曲热评数据
        isplaying:false,   //黑胶碟片动画播放状态,false为不播放
        ismv:false,    //遮罩层的显示状态,默认false不显示
        mvurl:"",  //mv播放地址
    },
    methods: {
        searchMusic:function(){   //获取歌曲列表
            var that=this;
            axios.get("https://autumnfish.cn/search?keywords="+this.query)
            .then(function(response){
                //console.log(this.query);   //打印query参数,看是否双向绑定成功
                //console.log(response);    //打印response,看打印出来的数据的层级关系
                //console.log(response.data.result.songs)   //打印此部分看层级关系是否正确,是否取到应该获取到的数据
                that.musicList=response.data.result.songs;   //使用musicList来保存取到的歌曲列表
            },
            function(err){
                console.log(err);
            })
        },
        musicPlayer:function(id){   //获取歌曲的url
            var that=this;
            axios.get("https://autumnfish.cn/song/url?id="+id)
            .then(function(response){
               // console.log(response);
                that.musicurl=response.data.data[0].url;
            },
            function(err){

            })
        },
        musicCover:function(id){  //获取歌曲的封面
            var that=this;
            axios.get("https://autumnfish.cn/song/detail?ids="+id)
            .then(function(response){
                //console.log(response);   //打印response,看打印出来的数据的层级关系
                //console.log(response.data.songs[0].al.picUrl);  //打印封面地址
                that.musiccover=response.data.songs[0].al.picUrl;   //赋值
                
            },
            function(err){

            })
        },
        musicComments:function(id){  //获取热评数据
            var that=this;
            axios.get("https://autumnfish.cn/comment/hot?type=0&id="+id)
            .then(function(response){
                console.log(response);
                that.musichotcomments=response.data.hotComments;
            },
            function(err){

            })
        },
        play:function(){  //播放状态播放动画
            this.isplaying=true;
        },
        puase:function(){ //暂停状态停止动画
            this.isplaying=false;
        },
        musicmv:function(mvid){   //mv播放
            var that=this;
            axios.get("https://autumnfish.cn/mv/url?id="+mvid)
            .then(function(response){
                console.log(response);   //打印获取的mv信息
                that.mvurl=response.data.data.url;   //获取到的mv地址
                that.ismv=true;
            },
            function(err){

            })
        },
        hide:function(){   //隐藏mv播放器
            this.puase();
            this.ismv=false;
        }
       
    }
    
})

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐