Vue3+node.js网易云音乐实战项目(五)

实现效果
在这里插入图片描述

1、推荐歌单详细页面

1.1、导航条和背景

推荐歌单页面做好后,我们开始做它的详细页面

Screenshot_2022-06-17-09-03-18-066_com.netease.cloudmusic

首先,我们设置一下路由,在views中新建一个ListView.vue的文件

image-20220617100440339

然后我们在router文件夹下index.js设置

{
    path: '/listview',
    name: 'listview',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/ListView.vue')
  }

image-20220617100526669

然后,我们来到components下的recommendMusic.vue下设置路由跳转

image-20220617100628028

看看下效果

3546242423213

然后,我们统一的调整一下a标签的颜色,在App.vue中设置一下

  // 设置跳转的颜色和下划线
  a{
    color: #333;
    text-decoration: underline;
  }

设置好后,我们需要知道跳转到对应的歌单上,所以我们可以看到参数里面有个对应的id

image-20220617101347622

我们把这个id传过去就能对应到我们不同的页面,我们把这个id也传过去

image-20220617101532402

image-20220617101544511

那么我们通过这个id,先把每日推荐的歌曲给拿到

image-20220617101824431

那我们就先把api封装一下,在api文件夹下index.js中

注意这里的baseURL,指 http://localhost:3000 ,我把它拿出来了

function postPlaylistDetail(id){
    return axios.post(`${baseUrl}/playlist/detail?id=${id}`)
 }

然后我们在Views文件夹下的ListView.vue中测试一下

<script>
import {postPlaylistDetail} from '@/api/index';
import { onMounted ,reactive} from 'vue';
import {useRoute} from 'vue-router'
export default {
 setup(){
     const route = useRoute()
     let state = reactive ({
         list:[]
         })
         
     onMounted(async()=>{
        //  获取传入的id
         let id = route.query.id

         let result = await postPlaylistDetail(id)
         console.log(result);
     })
 }
}
</script>

image-20220617104033828

结果请求出来后我们开始来写页面部分,首先就是顶部部分

image-20220617104628612

为了便于区分,我在components下创建了一个listView.vue的文件夹防止推荐歌单详细页面的vue

image-20220617105202973

然后我们在ListView.vue中注册一下主键

image-20220617105255307

然后我们在listviewTop.vue中写结构,引入图标(图标根据自己在iconfont下载的名字为主)

<template>
    <div class="listViewTop">
        <div class="listViewTopNav">
            <div class="left">
                <!-- 返回按钮 -->
                <div class="back">
                    <svg class="icon" aria-hidden="true">
                        <use xlink:href="#icon-xitongfanhui"></use>
                    </svg>
                </div>
                <!-- 歌单 -->
                <div class="title">
                    歌单
                </div>
            </div>
            <!-- 搜索按钮 和 更多按钮-->
            <div class="right">
                <div class="search">
                    <svg class="icon" aria-hidden="true">
                        <use xlink:href="#icon-sousuo"></use>
                    </svg>
                </div>
                <div class="more">
                    <svg class="icon" aria-hidden="true">
                        <use xlink:href="#icon-gengduo-shuxiang"></use>
                    </svg>
                </div>
            </div>
        </div>
    </div>
</template>

image-20220617110448776

然后我们来调整格式,设置整体的宽高和边距

<style lang="less" scoped>
.listViewTop{
    width: 7.5rem;
    padding: 0 0.4rem;
    height: 6rem;
}
</style>

image-20220617111257689

在利用flex从像两边靠

    .listViewTopNav{
        display: flex;
        justify-content: space-between;
        align-items: center;
        height: 1.2rem;
        font-size: 0.35rem;
    }

image-20220617111416945

在调整给左右两边的盒子调整为flex

    .left,.right{
        display: flex;
    }

image-20220617111457555

调整一下图标大小,给它调整为白色

        .icon{
            width: 0.5rem;
            height: 0.5rem;
            fill: #fff;
        }

image-20220617111543765

然后我们调整一下元素之间的边距和字体颜色

        .title{
            margin-left: 0.4rem;
        }
        .search{
            margin-right: 0.5rem;
        }
        .left,.right{
            display: flex;
            color: #fff;
        }

image-20220618150524051

然后我们来调整页面的背景,很显然背景是一个图片模糊的

image-20220618151230010

那么我们把这个的值传给子组件listviewtop.vue

<listviewtop :playlist = "state.playlist"></listviewtop>

在子组件这边接收一下

export default {
    props:['playlist']
}

然后渲染一下

<img class="bg" :src="playlist.coverImgUrl" alt="">

image-20220618152432445

然后我们调整一下样式

    .bg{
        position:fixed;
        left:0;
        top: 0;
        width: 7.5rem;
        height: auto;
        z-index: -1;
        // 设置滤镜模糊
        filter: blur(150px);
    }

image-20220618152503266

1.2、头像和简介

接下来,我们来做头像和简介

image-20220624192151108

我们可以分析,主要就分为两个区域 左边头像区域和右边文字区域和图标区域,然后我们首先创建一个div盒子

        <!-- 头像 简介部分 -->
        <div class="content">
            <div class="content_left">
            </div>
            <div class="contnet_right">
            </div>
        </div>

image-20220624192821152

然后我们可以看到头像是分为上面一层和下面一层两层的,上面的就是我们获取的背景图像,下面的是和它相同色调的背景图像

image-20220624193154429

        <!-- 头像 简介部分 -->
        <div class="content">
            <div class="content_left">
                <!-- 头像 -->
                <div class="hp">
                    <img class="headPortrait" :src="playlist.coverImgUrl" alt="">
                </div>
                <!-- 头像下面的小方块 -->
                <div class="headPortraitBlock">
                    <img class="headPortraitBlockBG" :src="playlist.coverImgUrl" alt="">
                </div>
            </div>
            <div class="contnet_right">
            </div>
        </div>

然后我们给上层的一个div一个宽高区区分上下层

        .headPortrait{
                width: 2.5rem;
                height: 2.5rem;
                border-radius: 10%;
            }

image-20220624193559464

然后,这里我们让它们俩个重叠,利用position和z-index来重叠,给最上层的父元素给定一个position: relative,子元素设置为position: absolute

    .content_left{
        position: relative;
        // 头像
        .hp{
            position: absolute;
            z-index: 2;
            top: 8px;
        }
        .headPortrait{
                width: 2.5rem;
                height: 2.5rem;
                border-radius: 10%;
            }
	}

image-20220624193825584

然后我们调整下面的头像,首先它是一个圆角,并且稍微往左边移动一点点

        .headPortraitBlock{
            position: absolute;
            z-index: 1;
            left: 13px;
            // 隐藏超出的部分
            overflow: hidden;
            border-radius: 10px;
        }

image-20220624194245253

然后我们设置一下图片的大小,并且和背景一样扩散,然后尽量取中间的颜色

            .headPortraitBlockBG{
                width: 2rem;
                height: 2rem;
                background-size: cover;
                filter: blur(50px);
                // 局部放大取颜色
                transform: scale(3);
            }

image-20220624194701030

然后我们在设置左上角的播放量,这个播放量,我们在推荐页面的歌单写过,我们直接copy那里的代码,然后修改一下变量就可以了

                     <div class="count">
                        <span></span>
                        <!--播放量  -->
                        <span>{{formatNum(playlist.playCount)}}</span>
                    </div>

image-20220625151316698

         .count{
            position: absolute;
            right: 0.1rem;
            top: 0.1rem;
            font-size: 0.24rem;
            color:rgb(246,247,250);
            border-radius:10px;
            background-color: rgba(19, 19, 19, 0.2);
        }

image-20220625151349445

然后我们来实现右边的标题和简介部分

image-20220625151929145

上面的名字,我们通过传过来的参数可以知道就是name

image-20220625154313330

那我们先把布局调整好

            <div class="contnet_right">
                <div class="rightTop">
                <!-- 歌单用户姓名 -->
                    <div class="UserTitle">
                        <p>{{playlist.name}}</p>
                    </div>
                <!-- 更多图标 -->
                    <div class="contnet_right_more">
                        <svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-gengduo"></use>
                        </svg>
                    </div>
                </div>
                <!-- 用户头像和姓名 -->
                <div class="UserInfo"></div>
                <!-- 用户简介 -->
                <div class="UserAbout"></div>
            </div>

大概就是这样,后面有问题,我们在调整,我们先看看效果。

image-20220625154519225

接下来我们调整一下样式,首先还是利用flex,向两边靠。

    .contnet_right{
         width: 4rem;
        .rightTop{
            display: flex;
            justify-content: space-around;
        }

    }

image-20220625154956512

然后调整一下字体颜色大小和图标颜色

            .UserTitle{
                color: #fff;
                font-size: 15px;
            }
            .icon{
                
                fill: #fff;
                width: 0.5rem;
                height: 0.5rem;
            }

image-20220625155042674

然后,我们来做下面这部分内容

image-20220625161801466

首先,先看传过来的参数,找到我们需要的值

image-20220625161912535

这几个就是我们需要的,然后我们来搭框架。

                <!-- 用户头像和姓名 -->
                <div class="UserInfo">
                    <!-- 头像 -->
                    <div class="UserImg">
                        <img class="UserPortrait" :src="playlist.creator.avatarUrl">
                    </div>
                    <!-- 名称 -->
                    <div class="UserName">
                        <p>{{playlist.creator.nickname}}</p>
                    </div>
                    <!-- 关注图标 -->
                    <div class="UserAttention"></div>
                </div>
                <!-- 用户简介 -->
                <div class="UserAbout">
                    <p>{{playlist.description}}</p>
                </div>

image-20220625162232394

然后我们来调整格式,首先用户头像那一栏是一个横排列,然后用户图片是个圆形

        .UserInfo{
            display: flex;
            .UserPortrait{
                width: 0.5rem;
                height: 0.5rem;
                border-radius: 100%;
            }
        }

image-20220625162405709

然后我们来调整名字的大小和颜色,给一个居中效果和颜色

        .UserInfo{
            display: flex;
            color: rgba(255, 255, 255, 0.5);
            .UserName{
                height: 26px;
                padding-left: 4px;
                font-size: 10px;
                line-height: 26px;
            }
        }

image-20220625165206332

然后,这里我就出了一个错误,我们来看一下,当我们刷新页面的时候

image-20220625165258538

它说没有这个值,因为这是creator的数据,刚开始是一个空的,所以第一次渲染拿不到值,然后就报了这个错误,我们需要去ListView.vue下设置creator对象,解决问题。

image-20220625165558561

然后,我们来添加关注的样式,首先先把关注插入进来

                    <!-- 关注图标 -->
                    <div class="UserAttention">
                        <svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-plus"></use>
                        </svg>
                    </div>

image-20220625170939309

给它一个背景和宽高,高的话就和用户图片一样就行了,

            .UserAttention{
                width: 0.7rem;
                height: 0.5rem;
                background-color: rgba(207, 207, 207, 0.5);
                margin-left: 10px;
                border-radius: 12px;
            }

image-20220625171042435

然后调整一下图标的位置和颜色就可以了

            .UserAttention{
                width: 0.7rem;
                height: 0.5rem;
                background-color: rgba(207, 207, 207, 0.5);
                margin-left: 10px;
                border-radius: 12px;
                display: flex;
                .icon{
                    align-self: center;
                    margin:0 auto;
                    fill: rgba(255, 255, 255, 0.6);
                }
            }

image-20220625171131317

然后我们来调整下面简介部分,首先就是一个文字和图标的的布局。

                <!-- 用户简介 -->
                <div class="UserAbout">
                    <div class="description">
                        <p>{{playlist.description}}</p>
                    </div>
                    <div class="UserAboutMore">
                        <svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-gengduo1"></use>
                        </svg>
                    </div>
                </div>

image-20220626101325954

还是利用flex布局,让它变为一排,然后多余的字体隐藏,在调整一下颜色

        .UserAbout{
                display: flex;
                justify-content: space-around;
                margin-top: 0.3rem;
                width: 3.5rem;
                color: rgba(255, 255, 255, 0.5);
               .description{
                    width: 3rem;
                    font-size: 14px;
                    display: -webkit-box;
                    -webkit-line-clamp: 1;
                    -webkit-box-orient: vertical;
                    overflow: hidden;
                }
                .icon{
                    align-self: center;
                    margin:0 auto;
                    fill: rgba(255, 255, 255, 0.6);
                }
        }

image-20220626101501800

1.3、头部完整代码

<template>
    <div class="listViewTop">
        <img class="bg" :src="playlist.coverImgUrl" alt="">
        <div class="listViewTopNav">
            <div class="left">
                <!-- 返回按钮 -->
                <div class="back">
                    <svg class="icon" aria-hidden="true">
                        <use xlink:href="#icon-xitongfanhui"></use>
                    </svg>
                </div>
                <!-- 歌单 -->
                <div class="title">
                    歌单
                </div>
            </div>
            <!-- 搜索按钮 和 更多按钮-->
            <div class="right">
                <div class="search">
                    <svg class="icon" aria-hidden="true">
                        <use xlink:href="#icon-sousuo"></use>
                    </svg>
                </div>
                <div class="more">
                    <svg class="icon" aria-hidden="true">
                        <use xlink:href="#icon-gengduo-shuxiang"></use>
                    </svg>
                </div>
            </div>
        </div>
        <!-- 头像 简介部分 -->
        <div class="content">
            <div class="content_left">
                <!-- 头像 -->
                <div class="hp">
                    <img class="headPortrait" :src="playlist.coverImgUrl" alt="">
                     <div class="count">
                        <span>▷</span>
                        <!--播放量  -->
                        <span>{{formatNum(playlist.playCount)}}</span>
                    </div>
                </div>
                <!-- 头像下面的小方块 -->
                <div class="headPortraitBlock">
                    <img class="headPortraitBlockBG" :src="playlist.coverImgUrl" alt="">
                </div>
            </div>
            <div class="contnet_right">
                <div class="rightTop">
                <!-- 歌单用户姓名 -->
                    <div class="UserTitle">
                        <p>{{playlist.name}}</p>
                    </div>
                <!-- 更多图标 -->
                    <div class="contnet_right_more">
                        <svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-gengduo"></use>
                        </svg>
                    </div>
                </div>
                <!-- 用户头像和姓名 -->
                <div class="UserInfo">
                    <!-- 头像 -->
                    <div class="UserImg">
                        <img class="UserPortrait"  :src="playlist.creator.avatarUrl">
                    </div>
                    <!-- 名称 -->
                    <div class="UserName">
                        <p>{{playlist.creator.nickname}}</p>
                    </div>
                    <!-- 关注图标 -->
                    <div class="UserAttention">
                        <svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-plus"></use>
                        </svg>
                    </div>
                </div>
                <!-- 用户简介 -->
                <div class="UserAbout">
                    <div class="description">
                        <p>{{playlist.description}}</p>
                    </div>
                    <div class="UserAboutMore">
                        <svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-gengduo1"></use>
                        </svg>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
import { computed } from 'vue'
export default {
    props:['playlist'],
    setup(){
     // 格式化输出听歌人数
        const formatNum = computed(()=>{
           return function(num){
                if(num>10000) return (num/10000).toFixed(2) + '万'
            }
        })
        return {
            formatNum
        }
    }
}
</script>

<style lang="less" scoped>
.listViewTop{
    width: 7.5rem;
    padding: 0 0.4rem;
    .bg{
        position:fixed;
        left:0;
        top: 0;
        width: 7.5rem;
        height: auto;
        z-index: -1;
        // 设置滤镜模糊
        filter: blur(150px);
        // transform: scale(4);
    }
    .listViewTopNav{
        display: flex;
        justify-content: space-between;
        align-items: center;
        height: 1.2rem;
        font-size: 0.35rem;
        .icon{
            width: 0.5rem;
            height: 0.5rem;
            fill: #fff;
        }
        .title{
            margin-left: 0.4rem;
        }
        .search{
            margin-right: 0.5rem;
        }
    }
    .left,.right{
        display: flex;
        color: #fff;
    }


    // 标题 头像部分
    .content{
        display: flex;
        justify-content: space-between;
        margin-top: 10px;
    }
    // 左边头像部分
    .content_left{
        position: relative;
        // 头像
        .hp{
            position: absolute;
            z-index: 2;
            top: 8px;
        }
        .headPortrait{
                width: 2.5rem;
                height: 2.5rem;
                border-radius: 10%;
            }
        .headPortraitBlock{
            position: absolute;
            z-index: 1;
            left: 13px;
            // 隐藏超出的部分
            overflow: hidden;
            border-radius: 10px;
            .headPortraitBlockBG{
                width: 2rem;
                height: 2rem;
                background-size: cover;
                filter: blur(50px);
                // 局部放大取颜色
                transform: scale(3);
            }
        }
         .count{
            position: absolute;
            right: 0.1rem;
            top: 0.1rem;
            font-size: 0.24rem;
            color:rgb(246,247,250);
            border-radius:10px;
            background-color: rgba(19, 19, 19, 0.2);
        }
    }

    // 右边歌单名和用户简介部分
    .contnet_right{
         width: 4rem;
         height: 2.5rem;
        .rightTop{
            display: flex;
            justify-content: space-around;
            height: 1.25rem;
            .UserTitle{
                color: #fff;
                font-size: 15px;
            }
            .icon{
                fill: #fff;
                width: 0.5rem;
                height: 0.5rem;
            }
        }
        // 用户信息
        .UserInfo{
            display: flex;
            color: rgba(255, 255, 255, 0.5);
            .UserPortrait{
                width: 0.5rem;
                height: 0.5rem;
                border-radius: 100%;
            }
            .UserName{
                height: 26px;
                padding-left: 4px;
                font-size: 10px;
                line-height: 26px;
            }
            .UserAttention{
                width: 0.7rem;
                height: 0.5rem;
                background-color: rgba(207, 207, 207, 0.5);
                margin-left: 10px;
                border-radius: 12px;
                display: flex;
                .icon{
                    align-self: center;
                    margin:0 auto;
                    fill: rgba(255, 255, 255, 0.6);
                }
            }
        }
        // 用户简介
        .UserAbout{
                display: flex;
                justify-content: space-around;
                margin-top: 0.3rem;
                width: 3.5rem;
                color: rgba(255, 255, 255, 0.5);
               .description{
                    width: 3rem;
                    font-size: 14px;
                    display: -webkit-box;
                    -webkit-line-clamp: 1;
                    -webkit-box-orient: vertical;
                    overflow: hidden;
                }
                .icon{
                    align-self: center;
                    margin:0 auto;
                    fill: rgba(255, 255, 255, 0.6);
                }
        }
    }

}
</style>

1.4、链接

Vue3+node.js网易云音乐实战项目(一): https://blog.csdn.net/NITIQ/article/details/125358363?spm=1001.2014.3001.5501
Vue3+node.js实战项目网易云音乐APP(二): https://blog.csdn.net/NITIQ/article/details/125358401?spm=1001.2014.3001.5502
Vue3+node.js网易云音乐实战项目(三): https://blog.csdn.net/NITIQ/article/details/125358446?spm=1001.2014.3001.5502
Vue3+node.js网易云音乐实战项目(四): https://blog.csdn.net/NITIQ/article/details/125358476?spm=1001.2014.3001.5502

未完…

  • 6
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

周粥粥ya

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

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

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

打赏作者

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

抵扣说明:

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

余额充值