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>
View Code

因为这是个子路由组件,需要在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,
    };
  },

posted @ 2021-06-29 15:09  小风车吱呀转  阅读(241)  评论(0编辑  收藏  举报