009_Vue音乐播放器(歌单详情页面的开发)

由于 QQ音乐的歌曲文件时不时更新一下,我在尝试了获取vkey后仍然是不能播放歌曲,所以我把歌单的数据换成了酷狗的API,酷狗API请求歌曲简单多了,在推荐组件下请求歌单,返回歌单的id,然后根据某一歌单的id可以请求回这个歌单下的所有歌曲的一些基本信息,根据基本信息下包含的hash值,可以请求回来这首歌曲的完整信息,包括可以直接播放的play_url 地址

页面结构还是和之前差不多,不过数据属性名有点差异

请求函数换成酷狗的

引入请求酷狗歌单的函数

import axios from 'axios';

let commonParams = {
  inCharset: 'utf-8',
  outCharset: 'utf-8'
}

export function getKugouDiscList() {
  const url = 'KugouMusicAPI/plist/index&json=true'
  const data = Object.assign({}, commonParams, {

  })
  return axios.get(url, {
    params: data
  }).then((res) => { //成功的回调
    return Promise.resolve(res.data.plist.list.info)
  })
}

由于这个请求只是单纯的跨域了,所以使用proxyTable 进行代理请求即可跨域访问

把请求回来的数据进行处理,然后转存在组件的data中

.

完成酷狗音乐歌单的请求,效果页

然后给每个歌单的li项,绑定点击事件,通过路由参数来传递数据(尽量不用vuex),实现路由跳转到歌单详情页

路由配置信息

跳转到歌单详情页 disc.vue,其中有用到musicList和songList组件,由于之前是QQ音乐API,现在是酷狗,所以我把这两个组件重新弄了一份kugouMusicList.vue和kugouSongList.vue,大部分结构保持不变,只是为了保证页面组件的可阅读性。在disc组件中,通过路由参数id,使用proxyTable 进行代理请求即可跨域访问。

disc.vue

<template>
  <div class="disc">
    <KugoumusicList
      :bgImage="this.$route.params.imgurl"
      :songs="disc.info"
      :title="this.$route.params.specialname"
    ></KugoumusicList>
  </div>
</template>

<script>
import KugoumusicList from "../../components/music-list/KugouMusic-list";
import { getKugouDiscList } from "../../api/kugouDisc"; //获取歌单下的歌曲

import { mapMutations } from "vuex";
import { mapGetters } from "vuex";

export default {
  data() {
    return {
      specialid: this.$route.params.id, //传入的歌单id,以发送axios请求,获取该歌单下的所有歌曲
      kugouDiscList: []
    };
  },
  created() {
    this._getKugouDiscList();
  },
  methods: {
    async _getKugouDiscList() {
      if (!this.$route.params.imgurl && !this.$route.params.specialname) {
        //刷新页面导致params数据丢失,返回到推荐页
        this.$router.push("/home/recommend");
      }

      this.kugouDiscList = await getKugouDiscList(this.specialid);
      this.setDisc(this.kugouDiscList); //vuex设置歌单数据
    },

    //设置歌单
    ...mapMutations({
      setDisc: "set_disc" //设置歌单信息
    })
  },
  components: {
    KugoumusicList
  },
  computed: {
    ...mapGetters(["disc"])
  },

};
</script>

<style>
.disc {
  position: absolute;
  width: 100%;
  height: 100vh;
  top: 0;
  color: black;
  background-color: white;
}
</style>

 

kugouMusicList.vue

<template>
  <div class="music-list">
    <div class="imgDiv">
      <!-- 顶部返回和标题 -->
      <header class="backgroundDiv">
        <div @click="goBack" class="el-icon-arrow-left goBack"></div>
        <span class="title">{{title}}</span>
      </header>
      <!-- <img v-lazy="bgImage" class="bgImage" ref="bgImage" /> -->
      <div class="bgImage" ref="bgImage" :style="bgStyle"></div>
    </div>
    <div
      ref="list"
      class="songList flexUl"
      v-loading="songs&&!songs.length"
      element-loading-text="拼命加载中"
      element-loading-spinner="el-icon-loading"
      element-loading-background="rgba(255,255,255, 0.8)"
      element-loading-customClass="loadingCustomClass"
      style="position:relative;min-height:50vh;font-size:1rem"
    >
      <KugouSongList :songs="songs" @select="selectItem"></KugouSongList>

      <!-- <player></player> -->
    </div>
  </div>
</template>

<script>
import scroll from "../base/scroll";
import KugouSongList from "../../components/base/KugouSongList";
import { mapActions } from "vuex";
import player from "../../components/player/player";

export default {
  props: {
    bgImage: {
      type: String,
      default: ""
    },
    songs: {
      type: Array,
      default: ()=>{}
    },
    title: {
      type: String,
      default: ""
    }
  },
  data() {
    return {};
  },
  methods: {
    goBack() {
      this.$router.go(-1);
    },
    selectItem(item, index) {
      //使用mapActions 暴露出来的 selectPlay函数,来设置播放器的播放内容
      this.selectPlay({
        list: this.songs, //为何不直接使用 item ,item在当前组件表示点击的某首歌曲,
        //此处传入的list将整个songs列表都传递进去,可以通过index查找,比起单首歌曲的播放列表,
        //显然完整的歌曲列表更加方便后续的使用
        index:index
      });
    },
    ...mapActions(["selectPlay"])
  },
  components: {
    scroll,
    KugouSongList,
    player
  },
  computed: {
    bgStyle() {
      return `background-image:url(${this.bgImage});background-size:cover;`;
    }
  }
};
</script>

<style lang="less" scoped>

kugouSongList.vue

<template>
  <div class="songList">
    <ul v-if="songs" :style="isPaddingBottom">
      <li @click="selectItem(item,index)" v-for="(item,index) in songs" :key="'info-'+index">
        <div class="container">
          <h2 class="name">
            <span>{{index+1 | indexFilter}}、</span>
            {{item.filename}}
          </h2>
        </div>
      </li>
    </ul>
  </div>
</template>

<script>
import { mapGetters } from "vuex";
export default {
  props: {
    songs: {
      type: Array,
      default: () => {}
    }
  },
  data() {
    return {
    };
  },
  methods: {
    selectItem(item, index) {
      this.$emit("select", item, index); //让父组件去处理
    }
  },
  filters: {
    indexFilter: function(val) {
      if (val.toString().length == 1) {
        return "0" + val;
      } else {
        return val;
      }
    }
  },
  watch: {
    //   使用路由参数时,例如从 /user/foo 导航到 /user/bar,
    //   原来的组件实例会被复用。因为两个路由都渲染同个组件,
    //   比起销毁再创建,复用则显得更加高效。
    //   不过,这也意味着组件的生命周期钩子不会再被调用。
    fullScreen: function(newVal) {
      newVal == true
        ? (this.isPaddingBottom = "")
        : (this.isPaddingBottom = "padding-bottom:4.5rem");
    }
  },
  computed: {
    ...mapGetters(["playList", "fullScreen"]),
    isPaddingBottom: {
      get: function() {
        if (this.playList) {
          if (this.playList.length) {
            return this.fullScreen ? "" : "padding-bottom:4.5rem";
          }
        } else {
            return ""
        }
      },
      set: function(newValue) {}
    }
  }
};
</script>

<style lang="less" scoped>

 

其中涉及到的对vuex的数据的判断,是因为在player.vue播放器组件里有正常全屏播放器和迷你底部栏播放器,由于底部栏播放器固定在底部,会对歌单列表和歌单歌曲列表产生遮盖,因此使用playList数据来判断是否处于播放状态,和fullScreen数据判断是否处于全屏播放状态,以此来调整涉及到的组件的底部留空和better-scroll组件的height属性。

给歌单中的歌曲li项绑定点击事件,并将其抛给父组件处理

在父组件kugouMusicList中接收

并通过vuex来改变相关的数据(list和index)

其中mapActions和mapMutations和mapGetters一样,是vuex的辅助函数,通过在action.js文件中定义的selectPlay函数,可以对state多个数据进行操作(该函数集中了对所需数据的操作),但是action.js的主要作用是处理异步操作(mutation只能处理同步操作),具体请看vuex官方文档,此时我们便可以通过mapActions辅助函数引入selectPlay函数,通过传入我们的数据,来实现对state数据的更新。

效果页:

下一篇将详细介绍 player.vue 播放器组件的页面结构和数据请求

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值