一、图标列表界面
首先,我们看一下接口文档,看需要请求什么接口
然后我们在components下新建一个子组件
首先,先引用一下axios,请求一下接口看看是不是我们需要的图片
<script>
import axios from 'axios'
import {reactive} from 'vue'
export default {
setup(){
let images = reactive({
list:[]
})
axios.post(`http://localhost:3000/homepage/dragon/ball`).then((res)=>{
images.list = res.data.data
});
console.log(images);
return {
images
}
}
}
</script>
我们可以看到这些就是我们需要的图片,然后我们考虑渲染到页面上
首先,我们利用v-for循环,可以看到整个部分分为上面图片部分,和下面文字页面
<template>
<div class="swipe">
<span v-for="(ima,index) in images.list" :key="index">
<img :src="ima.iconUrl"/>
<p>{{ima.name}}</p>
</span>
</div>
</template>
效果大概就是这个样子
然后我们首先考虑就是把它变为横排列并且可以滑动,利用 flex 和 overflow-y
.swipe {
display: flex;
overflow-y: auto;
text-align: center;
}
效果
然后我们需要取消下面的滑动条,利用伪对象选择器
.swipe::-webkit-scrollbar {
display: none;
}
效果已经很接近了,然后我们稍微调一下图片背景颜色,并变成圆形
img{
width: 1rem;
height: 1rem;
border-radius: 100%;
background: rgb(254,90,89);
}
可以看出来很紧凑,我们调一下边距 和字体大小
.swipe span {
margin: 18px 0px 0px 18px;
}
.swipe p {
font-size: 0.1rem;
align-items: center;
opacity: 0.7;
}
效果就出来了
然后我们挪一下请求代码,同样在api文件夹里面的index.js下
//圆形图标入口列表
function postIcon(){
return axios.post(`http://localhost:3000/homepage/dragon/ball`).then((res)=>{
return res.data.data
});
}
修改一下iconList.vue里的代码
<script>
import {postIcon} from '@/api/index'
import {reactive,onMounted} from 'vue'
export default {
setup(){
let images = reactive({
list:[]
})
onMounted(()=>{
getSwipeAPI()
})
// 获取入口图片
async function getSwipeAPI(){
images.list = await postIcon()
}
return {
images
}
}
}
</script>
完整代码
<template>
<div class="swipe">
<span v-for="(ima,index) in images.list" :key="index">
<img :src="ima.iconUrl"/>
<p>{{ima.name}}</p>
</span>
</div>
</template>
<script>
import {postIcon} from '@/api/index'
import {reactive,onMounted} from 'vue'
export default {
setup(){
let images = reactive({
list:[]
})
onMounted(()=>{
getSwipeAPI()
})
// 获取入口图片
async function getSwipeAPI(){
images.list = await postIcon()
}
return {
images
}
}
}
</script>
<style lang="less" scoped>
img{
width: 1rem;
height: 1rem;
border-radius: 100%;
background: rgb(254,90,89);
}
.swipe {
display: flex;
overflow-y: auto;
text-align: center;
}
.swipe::-webkit-scrollbar {
display: none;
}
.swipe span {
margin: 18px 0px 0px 18px;
}
.swipe p {
font-size: 0.1rem;
align-items: center;
opacity: 0.7;
}
</style>
二、推荐歌单界面
接下来,我们实现推荐歌单部分
我们可以看到推荐歌单主要由上面的导航栏部分和下面的图片部分组成
我们首先实现上面部分,在components中创建一个recommendMusic.vue的子组件
里面填上基本的结构
<template>
<!-- 每日推荐和推荐歌单中间的线条 -->
<van-divider />
<div class="musicList">
<!-- 顶部推荐歌单 -->
<div class="musicList-top">
<div class="title">推荐歌单</div>
<div class="more">
更多<van-icon name="arrow" />
</div>
</div>
<!-- 歌单部分 -->
<div class="songList">
</div>
</div>
</template>
注意 和 是vant里面的分割线和图标,我忘记找返回图标了,所以就用了vant里面的
分割线有点不明显,大概效果就是这样,然后我们来调整样式,利用flex调整
.musicList-top{
display: flex;
justify-content: space-between;
margin: 5px 15px 10px 15px;
}
在调整 更多 的样式,把他字体变小然后给它加一个边框,再调整颜色
.more{
width: 50px;
height: 20px;
font-size: 10px;
border: 1px solid rgb(224, 224, 224);
border-radius: 10px;
text-align: center;
padding-left: 5px;
}
然后在调整左边的 推荐歌单,字体给它变粗一点
.title{
font-weight: 900;
}
然后我们来实现下面的部分
这个很像我们做的每日推荐的样式,我们还是来看一下接口数据,同样利用axios请求一下接口
<script>
import axios from 'axios'
export default {
setup(){
axios.post(`http://localhost:3000/recommend/resource`).then((res)=>{
console.log(res);
});
}
}
</script>
然后我们把请求的数据返回给页面
<script>
import axios from 'axios'
import {onMounted,reactive} from 'vue'
export default {
setup(){
let songlistResult = reactive({
list:[]
})
axios.post(`http://localhost:3000/recommend/resource`).then((res)=>{
songlistResult.list = res.data.recommend
})
return {songlistResult}
}
}
</script>
既然我们的需要的效果和每日推荐的效果差不多,我们就先复制上面的样式
<!-- 歌单部分 -->
<div class="songList">
<div class="imgs" v-for="(img,index) in songlistResult.list" :key="index" >
<img :src="img.picUrl"/>
<div class="count">{{img.playcount}}</div>
<p>{{img.name}}</p>
</div>
</div>
// 歌单部分样式
img{
width: 1rem;
height: 1rem;
border-radius: 100%;
background: rgb(254,90,89);
}
.songList {
display: flex;
overflow-y: auto;
text-align: center;
}
.songList::-webkit-scrollbar {
display: none;
}
.songList .imgs {
margin: 18px 0px 0px 18px;
}
.songList p {
font-size: 0.1rem;
align-items: center;
opacity: 0.7;
}
现在的效果就是上面这样,然后我们在来调整部分的样式
这里我调整了一下宽度和高度,然后把居中对齐取消,最后调整了一下边距
// 只展示修改的部分
img{
width: 2rem;
height: 2rem;
border-radius: 10%;
background: rgb(254,90,89);
}
.songList {
display: flex;
overflow-y: auto;
}
.songList .imgs {
margin: 10px 0px 0px 10px;
}
接着我们把听音乐的人数调整一下,利用相对定位和绝对定位把人数固定在右上角
.songList .imgs {
margin: 10px 0px 0px 10px;
position: relative;
}
.count{
position: absolute;
right: 0.1rem;
top: 0.1rem;
font-size: 0.24rem;
color:rgb(246,247,250) ;
}
然后我们在稍微的调整一下,给他加个小三角形,这里我偷个懒直接用win10自带的输出法里面的三角形,在调整一下背景颜色
<span>▷</span>
.count{
position: absolute;
right: 0.1rem;
top: 0.1rem;
font-size: 0.24rem;
color:rgb(246,247,250);
border-radius:10px;
//a代表透明度
background-color: rgba(19, 19, 19, 0.4);
}
然后我们在给他加个万,利用computed计算属性,去对数字进行格式化操作
// 格式化输出听歌人数
const formatNum = computed(()=>{
return function(num){
if(num>10000) return (num/10000).toFixed(2) + '万'
}
})
然后我们在整理一下,请求接口,同样把请求丢在api/index.js里面
// 推荐歌单
function postRecommendMusic(){
return axios.post(`http://localhost:3000/recommend/resource`).then((res)=>{
return res.data.recommend
})
}
整理一下.vue的js代码
<script>
import {postRecommendMusic} from '@/api/index'
import {onMounted,reactive,computed} from 'vue'
export default {
setup(){
let songlistResult = reactive({
list:[]
})
onMounted(()=>{
getRecommendMusicAPI()
})
// 格式化输出听歌人数
const formatNum = computed(()=>{
return function(num){
if(num>10000) return (num/10000).toFixed(2) + '万'
}
})
// 请求数据
async function getRecommendMusicAPI(){
songlistResult.list = await postRecommendMusic()
}
return {songlistResult,formatNum}
}
}
</script>
完整代码
<template>
<!-- 每日推荐和推荐歌单中间的线条 -->
<van-divider />
<div class="musicList">
<!-- 顶部推荐歌单 -->
<div class="musicList-top">
<div class="title">推荐歌单</div>
<div class="more">
更多<van-icon name="arrow" />
</div>
</div>
<!-- 歌单部分 -->
<div class="songList">
<div class="imgs" v-for="(img,index) in songlistResult.list" :key="index" >
<img :src="img.picUrl"/>
<div class="count">
<span>▷</span>
<span>{{formatNum(img.playcount)}}</span>
</div>
<p>{{img.name}}</p>
</div>
</div>
</div>
</template>
<script>
import {postRecommendMusic} from '@/api/index'
import {onMounted,reactive,computed} from 'vue'
export default {
setup(){
let songlistResult = reactive({
list:[]
})
onMounted(()=>{
getRecommendMusicAPI()
})
// 格式化输出听歌人数
const formatNum = computed(()=>{
return function(num){
if(num>10000) return (num/10000).toFixed(2) + '万'
}
})
// 请求数据
async function getRecommendMusicAPI(){
songlistResult.list = await postRecommendMusic()
}
return {songlistResult,formatNum}
}
}
</script>
<style lang="less" scoped>
// 推荐歌单部分样式
.musicList-top{
display: flex;
justify-content: space-between;
margin: 5px 15px 10px 15px;
.title{
font-weight: 900;
}
.more{
width: 50px;
height: 20px;
font-size: 10px;
border: 1px solid rgb(224, 224, 224);
border-radius: 10px;
text-align: center;
padding-left: 5px;
}
}
// 歌单部分样式
.songList {
display: flex;
overflow-y: auto;
}
img{
width: 2rem;
height: 2rem;
border-radius: 10%;
background: rgb(254,90,89);
}
.songList::-webkit-scrollbar {
display: none;
}
.songList .imgs {
margin: 10px 0px 0px 10px;
position: relative;
}
.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.4);
}
.songList p {
font-size: 0.1rem;
align-items: center;
opacity: 0.7;
}
</style>
三、链接
Vue3+node.js网易云音乐实战项目(一): https://blog.youkuaiyun.com/NITIQ/article/details/125358363?spm=1001.2014.3001.5501
Vue3+node.js实战项目网易云音乐APP(二): https://blog.youkuaiyun.com/NITIQ/article/details/125358401?spm=1001.2014.3001.5502
Vue3+node.js网易云音乐实战项目(三): https://blog.youkuaiyun.com/NITIQ/article/details/125358446?spm=1001.2014.3001.5502
Vue3+node.js网易云音乐实战项目(四): https://blog.youkuaiyun.com/NITIQ/article/details/125358476?spm=1001.2014.3001.5502
未完…
未完…