vueJs开发音乐播放器第二篇(点击歌单跳出详情页)

继上一篇开发音乐播放器歌单列表页

1.使用router定义跳转链接,2. 使用axios得到音乐第三方数据,并渲染到页面上,3.组件之间传值(props)

1.接下来使用了vue-router路由动态传值,父子嵌套式路由 

this.$router.push({
path: `/recommend/${item.id}`
});

2.router入口文件定义路由路径:

3. 此时需要渲染路由在父组件中:

 B.使用vuex进行状态管理:

npm install vuex --save
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

定义一个state,getters,mutations,方便组件中使用:

export 导出vuex定义模块

第二栏效果图:

主要代码:

<template>
<div >
   <div class="wrapper" ref='wrapper'>
   <div class="content">
       <listview 
       title="推荐歌单" 
       :showPlayCount="true" 
       :showSinger="false" 
       :limit="6"
    :resources="recommendList"
       @select="selectedList"></listview>
    <listview 
    title="最In音乐"
    :showPlayCount="false"
    :showSinger="true"
    :limit="6"
    :resources="newList"
    @select="selectedList"></listview>
    <listview
    title="主播电台"
    :showPayCount="false"
    :showSinger="true"
    :limit="6"
    :resources="djrecommend"
    @select="selectedList"></listview>
   </div>
   <router-view></router-view>
</div>
  
  </div>
</template>
<script>
  import Listview from '@/components/listview/listview'
  import {mapGetters, mapMutations} from 'vuex'
  import store from "@/store/store.js";
  export default{
      name:"recommend",
    store,
      data(){
          return {
              list:null
          }

      },
      components:{
          Listview,
      
      },
      methods: {
    //定义selectedList方法,router.push路由跳转
      selectedList(item) {
        this.$router.push({
          path: `/recommend/${item.id}`
        });
        console.log(item);
        this.setSongList(item);
      },
      ...mapMutations([
        'setSongList'
      ])

    },
       created(){
            /*this.axios
            .get('http://localhost:3000/top/playlist/highquality')
            .then((response)=>{
                this.list = response.data.playlists

                // console.log(this.list)
            })
            .catch((response)=>{
                console.log(response)
            })*/
            this.recommendList = 'http://localhost:3000/top/playlist/highquality';
            this.newList='http://localhost:3000/top/playlist?order=hot';
            this.djrecommend='http://localhost:3000/personalized/djprogram';
      }


  }  
</script>
<style lang="scss" rel="style/scss">

    
</style>
歌单列表页
<template>
  <transition name="fade">
  <music-list :songs="songs" :id="id">
  </music-list>
</transition>
</template>

<script>
  import {mapGetters} from 'vuex';
  import musicList from '@/components/music-list/music-list'

  export default {
    name: "list-detail",
    data() {
      return {
        songs: {},
        id: ''
      }
    },
    created() {
      this._getSongList();
    },
    methods: {
      _getSongList() {
        if (!this.songList || !this.songList.id) {
          this.$router.push('/recommend');
          return;
        }
      //使用vuex定义的数据得到父组件的相关值
        this.songs = this.songList;
        this.id = this.songList.id;
      },
    },
    computed: {
      ...mapGetters([
        'songList'
      ])
    },
    components: {
      musicList
    },

  }
</script>

<style lang="scss">
  .fade-enter-active, .fade-leave-active {
    transition: all 0.3s;
  }

  .fade-enter, .fade-leave-to {
    opacity: 0;
  }


</style>
子组件传值给歌曲列表页
<template>
  <div class="music-list">
    <div class="header">
      <div class="header-img">
        <img :src="songs.coverImgUrl">
        <div class="play-count"><i class="icon iconfont icon-headset"></i>{{songs.playCount|unitConvert}}</div>
        <div class="detail-btn"><i class="icon iconfont icon-detail"></i></div>
      </div>
      <div class="header-content">
        <div class="name">{{songs.name}}</div>
        <div class="tags" v-show="songs.tags">
          <span>标签: </span><span class="tag" v-for="(tag,idx1) in songs.tags" :key="idx1">{{tag}}</span>
        </div>
        <div class="subname" v-if="songs.subscribers && songs.subscribers.length > 0">
          {{songs.subscribers[0].nickname}}<span class="create-time">创建于{{songs.createTime}}</span>
        </div>
      </div>
      <div class="back" @click="back">
        <i class="icon iconfont icon-close"></i>
      </div>
      <div class="background">
        <img :src="songs.coverImgUrl">
      </div>
    </div>
    <div class="body">
      <div class="header-bar">
        <i class="icon iconfont icon-play"></i><span class="playAll">播放全部<i
        class="count">(共{{detail.length}}首)</i></span>
        <span class="collect"><i class="icon iconfont icon-add"></i>收藏({{subscribedCount|unitConvert}})</span>
      </div>
      <div class="songList-wrapper" ref="listWrapper">
        <ul class="songlist">
            <li class="song-item" v-for="(item, idx) in detail" :key="idx" @click="selectItem(item, idx, $event)">
              <div class="line-number">
                <span>{{idx+1}}</span>
              </div>
              <div class="item-content">
                <div class="songname">{{item.name}}</div>
                <div class="songer">{{item.ar[0].name}} - {{item.al.name}}</div>
              </div>
              <div class="tool">
                <i class="icon iconfont icon-tool"></i>
              </div>
            </li>
        </ul>

      </div>

    </div>

  </div>
</template>

<script>

  import {unitConvert} from '@/common/js/unitConvert'
  import {mapGetters, mapActions} from 'vuex'


  export default {
    name: "music-list",
   //得到list-detail传过来的id,并获取第三方数据,渲染到页面中
    props: {
      songs: {
        type: Object
      },
      id: {
        type: [String, Number]
      }
    },
    data() {
      return {
        detail: [],
        subscribedCount: ''
      }
    },
    created() {
      if (this.id) {
        let url = `http://localhost:3000/playlist/detail?id=${this.id}`;
        this.axios.get(url).then((res) => {
          this.detail = res.data.playlist.tracks;
          this.subscribedCount = res.data.playlist.subscribedCount;

        })
      } 
       
    },
    methods: {
      back(){

      },
      ...mapActions([
        'selectPlay'
      ])
    },
    filters: {
      unitConvert(num) {
        return unitConvert(num);
      }
    }
  }
</script>

<style lang="scss">
@function px2rem($px) {
  @return $px / 30 + rem;
}
  .music-list {
    position: fixed;
    z-index: 200;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    background: #fff;
    .header {
      position: relative;
      display: flex;
      width: 100%;
      height: px2rem(400);
      align-items: center;
      overflow: hidden;
      background-color: rgba(0, 0, 0, 0.2);
      .header-img {
        display: flex;
        position: relative;
        justify-content: center;
        flex: 0 0 px2rem(300);
        width: px2rem(300);
        height: px2rem(250);
        img {
          width: px2rem(250);
          height: px2rem(250);
        }
        .play-count {
          position: absolute;
          top: 0;
          right: px2rem(40);
          color: #fff;
          font-size: px2rem(24);
          font-weight: bold;
          .icon-headset {
            color: #fff;
            font-size: px2rem(24);
            font-weight: bold;
            margin-right: px2rem(8);
          }
        }
        .detail-btn {
          position: absolute;
          bottom: 0;
          right: px2rem(42);
          color: #fff;
          .icon-detail {
            font-size: px2rem(36);
            font-weight: bold;

          }
        }
      }
      .header-content {
        flex: 1;
        height: px2rem(250);
        padding-right: px2rem(25);
        color: #fff;
        .name {
          margin: px2rem(20) 0;
          height: px2rem(90);
          font-size: px2rem(32);
          font-weight: bold;
        }
        .tags {
          margin-bottom: px2rem(24);
          font-size: px2rem(26);
          line-height: px2rem(26);
          height: px2rem(26);
          .tag {
            padding: 0 px2rem(12);
            border: 2px solid #fff;
            border-radius: px2rem(8);
            margin-left: px2rem(12);
          }
        }
        .subname {
          font-size: px2rem(26);
          line-height: px2rem(26);
          height: px2rem(26);
          .create-time {
            margin-left: px2rem(10);
          }

        }

      }
      .icon-close {
        position: absolute;
        top: 0;
        right: px2rem(16);
        padding: px2rem(20);
        color: #fff;
        font-size: px2rem(32);
        font-weight: bold;
      }
      .background {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: px2rem(400);
        z-index: -1;
        filter: blur(px2rem(100));
        overflow: hidden;

      }
    }
    .body {
      .header-bar {
        display: flex;
        line-height: px2rem(80);
        height: px2rem(80);
        border-bottom: 1px solid #eee;
        justify-content: center;
        text-align: center;
        .icon-play {
          width: px2rem(80);
          font-size: px2rem(48);
        }
        .playAll {
          flex: 1;
          font-size: px2rem(26);
          text-align: left;
          .count {
            font-size: px2rem(24);
            font-style: normal;
            color: #7e8c8d;
          }
        }
        .collect {
          padding: 0 px2rem(24);
          background: #F93021;
          color: #fff;
          font-size: px2rem(26);
          font-weight: bold;
          text-align: center;
          .icon-add {
            font-size: px2rem(26);
            color: #fff;
            font-weight: bold;
          }
        }
      }
      .songList-wrapper {
        position: absolute;
        top: px2rem(480);
        bottom: 0;
        left: 0;
        width: 100%;
        overflow: hidden;
        .songlist {
          background: #fff;
          .song-item {
            display: flex;
            &.list-complete-enter-active, &.list-complete-leave-active {
              transition: all 0.2s linear;
            }
            &.list-complete-enter, &.list-complete-leave-to {
              opacity: 0;
              transform: translateY(px2rem(30));
            }
            .line-number {
              flex: 0 0 px2rem(80);
              width: px2rem(80);
              height: px2rem(80);
              line-height: px2rem(80);
              text-align: center;
              font-size: px2rem(30);
              color: #7e8c8d;

            }
            .item-content {
              flex: 1;
              border-bottom: 1px solid #eee;
              width: 80%;
              .songname {
                font-size: px2rem(28);
                overflow: hidden;
                white-space: nowrap;
                text-overflow: ellipsis;

              }
              .songer {
                font-size: px2rem(22);
                color: #7e8c8d;
                overflow: hidden;
                white-space: nowrap;
                text-overflow: ellipsis;

              }

            }
            .tool {
              flex: 0 0 px2rem(80);
              width: px2rem(80);
              line-height: px2rem(80);
              border-bottom: 1px solid #eee;
              text-align: center;
              .icon-tool {
                font-size: px2rem(30);

              }
            }

          }
        }
      }

    }
  }

</style>
歌曲列表页

router的相关定义:

import Vue from 'vue'
import Router from 'vue-router'
import Helloworld from '@/components/HelloWorld'
import Recommend from '@/page/recommend'
import HotRecommend from '@/page/hotrecommend'
import Search from '@/page/search'
//引入子组件
import recommendList from '@/page/list-detail'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      component: Helloworld
    },
    {
      path: '/recommend',
      component: Recommend,
  //子组件路由
      children: [
        {
          path: ':id',
          component: recommendList
        }
      ]
    },
    {
      path: '/Hotrecommend',
      component: HotRecommend
    },
    {
      path: '/search',
      component: Search
    }
  ]
})
嵌套式路由实用

vuex-- store.js设定:

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex)
const state = {
    // count:1,
    songList:null
}
const getters = {
    songList:function(state) {
        return state.songList;
    }
}
const mutations = {
    /*increment(state){
        state.count++
    },
    decrement(state){
        state.count--
    },*/
    setSongList(state,item) {
        state.songList=item;
    }
}
const actions={
    /*increment: ({commit})=>{
        commit('increment')
    },
    decrement: ({commit})=>{
        commit('decrement')
    },*/
/*    selectPlay: ({commit, state}, {list, index})=>{
        commit('setPlayList',list)
    },
*/
}

export default new Vuex.Store({
    state,
    mutations,
    getters,
    actions
})
state,mutations,getters定义
posted @ 2019-06-25 18:55  cheryshi  阅读(553)  评论(0编辑  收藏  举报