zoukankan      html  css  js  c++  java
  • 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定义
  • 相关阅读:
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    【手绘漫画】图解LeetCode之最长上升子序列(LeetCode300题),贪心算法 + 二分查找
    C 语言编程 — GDB 调试工具
    【debug】Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure.
    tf.expand_dims()函数解析(最清晰的解释)
    C 语言编程 — 堆栈与内存管理
    C 语言编程 — 输入/输出与文件操作
    C 语言编程 — 头文件
  • 原文地址:https://www.cnblogs.com/cheryshi/p/11084748.html
Copyright © 2011-2022 走看看