VUE移动端音乐APP学习【十九】:排行榜详情页开发
排行榜详情页和之前的歌手详情页、歌单详情页布局类似,除了数据不同之外还多了排行榜排名的样式,整体上还是可以复用之前的组件。
初始化代码:
<template> <transition name="slide"> <music-list></music-list> </transition> </template> <script> import musicList from '../music-list/music-list.vue'; export default { name: 'top-list', components: { musicList }, }; </script> <style lang="scss" scoped> .slide-enter-active, .slide-leave-active { transition: all 0.3s ease; } .slide-enter, .slide-leave-to { transform: translate3d(100%, 0, 0); } </style>
因为这是个子路由组件,需要在router.js里设置该路由。
import TopList from '../components/top-list/top-list'; //定义在rank的children下 { path: '/rank', name: 'Rank', component: Rank, children: [{ path: ':id', component: TopList, }], },
去rank.vue中实现点击跳转到toplist事件
<template> <div class="rank" ref="rank"> <scroll :data="topList" class="toplist" ref="toplist"> <ul> <li class="item" v-for="(item,index) in topList" :key="index" @click="selectItem(item)"> ...... </scroll> <router-view></router-view> </div> </template>
selectItem(item) { // 调用router的api this.$router.push({ path: `/rank/${item.id}`, }); },
在toplist.vue中通过获取路由参数(this.$route.params)获取到排行榜歌单详情列表
import { getSongList } from '../../api/recommend'; import { ERR_OK } from '../../api/config'; created() { this._getTopList(); }, data() { return { topList: [], }; }, methods: { _getTopList() { getSongList(this.$route.params.id).then((res) => { if (res.code === ERR_OK) { this.topList = res.playlist; console.log(this.topList); } }); }, },
在computed中设置标题和图片,把这2个数据传到music-list里面
<music-list :title="title" :bgImage="bgImage"></music-list> computed: { title() { return this.topList.name; }, bgImage() { return this.topList.coverImgUrl; }, },
接下来是处理排行榜歌单列表,需要使用createSong以及_normalizeSongs将数据实例化传到music-list中
<music-list :title="title" :bgImage="bgImage" :songs="songs"></music-list>
import { createSong } from '../../common/js/song'; data() { return { topList: [], songs: [], }; }, methods: { _getTopList() { getSongList(this.$route.params.id).then((res) => { if (res.code === ERR_OK) { this.topList = res.playlist; this.songs = this._normalizeSongs(this.topList.tracks); } }); }, _normalizeSongs(list) { let ret = []; list.forEach((item) => { if (item.id && item.al.id) { ret.push(createSong(item)); } }); return ret; }, },
封面可能看起来很丑,可以将其替换为第一首歌的图片
bgImage() { if (this.songs.length) { return this.songs[0].image; } return ''; },
最后是扩展榜单样式
- 在song-list中添加几张榜单图片并添加CSS样式
.rank { flex: 0 0 25px; width: 25px; margin-right: 30px; text-align: center; .icon { display: inline-block; width: 25px; height: 24px; background-size: 25px 24px; &.icon0 { @include bg-image('first'); } &.icon1 { @include bg-image('second'); } &.icon2 { @include bg-image('third'); } } .text { color: $color-theme; font-size: $font-size-large; } }
- props需要扩展一个字段rank,类型为boolean值
props: { songs: { type: Array, // eslint-disable-next-line vue/require-valid-default-prop default: [], }, rank: { type: Boolean, // 默认它是没有排行的样式 default: false, }, },
- 扩展dom:除了歌曲的名字和描述之外,扩展一个rank样式通过v-show决定是否显示以及设置它显示的样式和文本
<div class="song-list"> <ul> <li @click="selectItem(song,index)" v-for="(song,index) in songs" class="item" :key="song.id"> <div class="rank" v-show="rank"> <span :class="getRankCls(index)">{{getRankText(index)}}</span> </div> <div class="content"> <h2 class="name">{{song.name}}</h2> <p class="desc">{{getDesc(song)}}</p> </div> </li> </ul> </div>
//定义2个methods方法 getRankCls(index) { // 前3名就返回图片的样式 if (index <= 2) { return `icon icon${index}`;
} else { return 'text'; } }, // eslint-disable-next-line consistent-return getRankText(index) { if (index > 2) { return index + 1; } },
- 在music-list扩展这个rank字段,然后把这个rank传到songlist作为它的属性
<div class="song-list-wrapper"> <song-list :rank="rank" @select="selectItem" :songs="songs"></song-list> </div> rank: { type: Boolean, default: false, },
- 在调用music-list传递rank为true让它显示排行榜的样式
<transition name="slide"> <music-list :rank="true" :title="title" :bgImage="bgImage" :songs="songs"></music-list> </transition> data() { return { topList: [], songs: [], rank: true, }; },