zoukankan      html  css  js  c++  java
  • cloud-music

    非常感谢那些无私开源的程序员,希望我也能够有能力像你们那样,开源很多很有意思的东西~~

    //index.html
    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <title>cloud-music</title>
      <meta http-equiv=X-UA-Compatible content="IE=edge">
      <meta name=format-detection content="telephone=no">
      <meta name=format-detection content="email=no">
      <meta name=apple-mobile-web-app-capable content=yes>
      <meta name=apple-mobile-web-app-status-bar-style content=black>
      <meta name=full-screen content=yes>
      <meta name=browsermode content=application>
      <meta name=x5-orientation content=portrait>
      <meta name=x5-fullscreen content=true>
      <meta name=x5-page-mode content=app>
      <!--清除缓存-->
      <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
      <meta http-equiv="Pragma" content="no-cache" />
      <meta http-equiv="Expires" content="0" />
      <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,minimal-ui">
      <link rel="icon" href="static/logo.ico" type="image/x-icon" />
      <link rel="shortcut icon" href="static/logo.ico" type="image/x-icon" />
      <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic">
      <link href="http://cdn.bootcss.com/material-design-icons/3.0.1/iconfont/material-icons.min.css" rel="stylesheet">
      <script>
        ;(function (doc, win, undefined) {
              let docEl = doc.documentElement,
                resizeEvt = 'orientationchange' in win? 'orientationchange' : 'resize',
                recalc = function () {
                  let clientWidth = docEl.clientWidth;
                  if (clientWidth === undefined) return;
                  docEl.style.fontSize = 20 * (clientWidth / 320) + 'px';
                };
              if (doc.addEventListener === undefined) return;
              win.addEventListener(resizeEvt, recalc, false);
              doc.addEventListener('DOMContentLoaded', recalc, false)
            })(document, window);
      </script>
      <style>
        * {
          margin: 0;
          padding: 0;
        }
        a {
          text-decoration: none;
        }
        p, span {
          font-size: 12px;
        }
      </style>
    </head>
    <body>
    <div id="app">
      <keep-alive>
        <router-view v-if="$route.meta.keepAlive"></router-view>
      </keep-alive>
      <router-view v-if="!$route.meta.keepAlive"></router-view>
    </div>
    <script src="//cdn.bootcss.com/vue/2.2.5/vue.min.js"></script>
    <script src="//cdn.bootcss.com/vue-router/2.3.0/vue-router.min.js"></script>
    <script src="//cdn.bootcss.com/vuex/2.2.1/vuex.min.js"></script>
    <script src="//cdn.bootcss.com/axios/0.15.3/axios.min.js"></script>
    </body>
    </html>
    
    //app.vue
    <template>
      <div>
        <!-- 主界面部分 -->
        <loading :show="loadingShow"></loading>
        <keep-alive>
          <router-view v-if="$route.meta.keepAlive"></router-view>
        </keep-alive>
        <router-view v-if="!$route.meta.keepAlive"></router-view>
        <player v-show="songList.length > 0 && !showDetail"></player>
      </div>
    </template>
    <script>
      import player from './components/playerBar/playerBar';
      import loading from './components/loading/overall-loading';
      import { mapGetters } from 'vuex';
      export default {
        name: 'app',
        mounted () {
          console.log('%c 浅滩戏虾', 'background-image:-webkit-gradient( linear, left top,right top, color-stop(0, #00a419),color-stop(0.15, #f44336), color-stop(0.29, #ff4300),color-stop(0.3, #AA00FF),color-stop(0.4, #8BC34A), color-stop(0.45, #607D8B),color-stop(0.6, #4096EE), color-stop(0.75, #D50000),color-stop(0.9, #4096EE), color-stop(1, #FF1A00));color:transparent;-webkit-background-clip:text;font-size:13px;');
        },
        computed: {
          ...mapGetters([
            'songList',
            'showDetail',
            'loadingShow'
          ])
        },
        components: {
          player,
          loading
        }
      };
    </script>
    
    //main.js
    import Vue from 'vue';
    import store from './vuex';
    import VueRouter from 'vue-router';
    import VueLazyload from 'vue-lazyload';  // 引入图片懒加载模块
    import App from './App';
    import routes from './routers';
    // import {loadFromlLocal} from './common/js/store'; // 公共方法:本地缓存
    // 注册为全局组件
    Vue.use(VueRouter);
    // error,loading是图片路径, 用require引入
    Vue.use(VueLazyload, {
        error: require('./assets/404.png'),
        loading: require('./assets/loading.jpg'),
        attempt: 1
      }
    );
    
    const scrollBehavior = (to, from, savedPosition) => {
      if (savedPosition) {
        // savedPosition is only available for popstate navigations.
        return savedPosition;
      } else {
        let position = {};
        // new navigation.
        // scroll to anchor by returning the selector
        if (to.hash) {
          position.selector = to.hash;
        }
        // check if any matched route config has meta that requires scrolling to top
        if (to.matched.some(m => m.meta.scrollToTop)) {
          // cords will be used if no selector is provided,
          // or if the selector didn't match any element.
          position.x = 0;
          position.y = 0;
        }
        // if the returned position is falsy or an empty object,
        // will retain current scroll position.
        return position;
      }
    };
    
    const router = new VueRouter({
      // mode: 'history',
      'linkActiveClass': 'active',
      routes, // (缩写)相当于 routes: routes
      scrollBehavior
    });
    
    /**
     * 创建和挂载根实例。
     * 记得要通过 router 配置参数注入路由,
     * 从而让整个应用都有路由功能
     */
    const routerApp = new Vue({
      router,
      store,
      render: h => h(App)
    }).$mount('#app');
    
    /**
     * loadFromlLocal()是读取本地缓存数据,具体common/js/store.js 查看
     */
    // if (!loadFromlLocal('music', 'find', false)) {
    //   router.push('/find');
    // }
    export default routerApp;
    
    
    //router.js
    /**
     * 整个app的路由设置
     */
    const router = [{
      path: '/find',  //  引导页
      name: 'index',
      component (resolve) {
        require.ensure(['./views/index'], () => {
          resolve(require('./views/index'));
        });
      },
      children: [{
        path: '/find',  //  发现
        name: 'find',
        component (resolve) {
          require.ensure(['./views/find/find'], () => {
            resolve(require('./views/find/find'));
          });
        },
        meta: { keepAlive: true }
      }],
      meta: { keepAlive: true }
    }, {
      path: '/search',  //  搜索页
      name: 'search',
      component (resolve) {
        require.ensure(['./views/search/search'], () => {
          resolve(require('./views/search/search'));
        });
      },
      meta: { keepAlive: true }
    }, {
      path: '/player/:id', //  单曲播放页
      name: 'player',
      component (resolve) {
        require.ensure(['./views/detail/player/player'], () => {
          resolve(require('./views/detail/player/player'));
        });
      },
      meta: { keepAlive: false }
    }, {
      path: '/playLists/:id',  //  歌单详情页
      name: 'playLists',
      component (resolve) {
        require.ensure(['./views/detail/playList/playlists'], () => {
          resolve(require('./views/detail/playList/playlists'));
        });
      },
      meta: { keepAlive: false }
    }, {
      path: '/singer/:id',  //  歌手详情页
      name: 'singer',
      component (resolve) {
        require.ensure(['./views/detail/singer/singer'], () => {
          resolve(require('./views/detail/singer/singer'));
        });
      },
      meta: { keepAlive: false }
    }, {
      path: '/album/:id',  // 专辑详情页
      name: 'album',
      component (resolve) {
        require.ensure(['./views/detail/album/album'], () => {
          resolve(require('./views/detail/album/album'));
        });
      },
      meta: { keepAlive: false }
    }, {
      path: '/user/:id',  // 用户详情页
      name: 'user',
      component (resolve) {
        require.ensure(['./views/detail/user/user'], () => {
          resolve(require('./views/detail/user/user'));
        });
      },
      meta: { keepAlive: false }
    }, {
      path: '/ranking/:idx',  // 榜单详情页
      name: 'ranking',
      component (resolve) {
        require.ensure(['./views/detail/ranking/ranking'], () => {
          resolve(require('./views/detail/ranking/ranking'));
        });
      },
      meta: { keepAlive: false }
    }, {
      path: '/mv/:id',  // 视频播放
      name: 'mv',
      component (resolve) {
        require.ensure(['./views/detail/mvPlay/mvPlay'], () => {
          resolve(require('./views/detail/mvPlay/mvPlay'));
        });
      },
      meta: { keepAlive: false }
    }, {
      path: '/playListComment/:id',  // 歌单评论
      name: 'playListComment',
      component (resolve) {
        require.ensure(['./views/detail/playList/playListComment'], () => {
          resolve(require('./views/detail/playList/playListComment'));
        });
      },
      meta: { keepAlive: false }
    }, {
      path: '/albumComment/:id',  // 专辑评论
      name: 'albumComment',
      component (resolve) {
        require.ensure(['./views/detail/album/albumComment'], () => {
          resolve(require('./views/detail/album/albumComment'));
        });
      },
      meta: { keepAlive: false }
    }, {
      path: '/rankingComment/:id',  // 排行榜歌单评论
      name: 'rankingComment',
      component (resolve) {
        require.ensure(['./views/detail/ranking/rankingComment'], () => {
          resolve(require('./views/detail/ranking/rankingComment'));
        });
      },
      meta: { keepAlive: false }
    }, {
      path: '*', redirect: '/find' //  url错误重回定向
    }];
    export default router;
    
    
    //find.vue
    <template>
      <transition name="fade">
        <div class="find-page">
            <tab :line-width=2 active-color='#b72712' defaultColor='#666' bar-active-color='#b72712'
                 v-model="index">
                 <!-- 切换 -->
              <tab-item class="vux-center" :selected="type === item" v-for="(item, index) in tabList"
                        @click="type = item" :key="index" style="background-color: #fdfffe;">{{item}}
              </tab-item>
            </tab>
            <!-- 轮播切换的 -->
            <!-- 这个是左右的那种切换 -->
            <swiper v-model="index" height="100%" :show-dots="false" class="swiper-container" style="100%;height: 100%;padding-bottom: 90px;background-color: #eef2f1;">
              <swiper-item :key="1">
                <div class="tab-swiper vux-center">
                  <v-recommend></v-recommend>
                </div>
              </swiper-item>
              <swiper-item :key="2">
                <div class="tab-swiper vux-center">
                  <v-play-lists></v-play-lists>
                </div>
              </swiper-item>
              <swiper-item :key="3">
                <div class="tab-swiper vux-center">
                  <v-ranking></v-ranking>
                </div>
              </swiper-item>
            </swiper>
        </div>
      </transition>
    </template>
    <script>
      import { Tab, TabItem, Swiper, SwiperItem } from 'vux';
      import vRecommend from './recommend/recommend';
      import vPlayLists from './playLists/playLists';
      import vRanking from './ranking/ranking';
      //tabList:list()
      const list = () => ['个性推荐', '歌单', '排行榜'];
      export default {
        name: 'find',
        data () {
          return {
            index: 0,
            tabList: list(),
            type: '个性推荐'
          };
        },
        components: {
          vPlayLists,
          vRecommend,
          vRanking,
          Tab,
          TabItem,
          Swiper,
          SwiperItem
        }
      };
    </script>
    <style lang="stylus" rel="stylesheet/stylus" scoped>
      @import 'find.styl';
    </style>
    
    //activitysList.vue
    <template>
      <ul class="activitys-area">
        <li class="activity-card-find" v-for="(data, index) in activitys" :key="index">
          <img v-lazy="data.picUrl + '?param=400y200'" lazy="loading">
          <h2 style="-webkit-box-orient: vertical;">{{data.name}}</h2>
        </li>
      </ul>
    </template>
    <script>
      export default {
        name: 'v-activity-list',
        props: {
          activitys: {
            type: Array,
            default: []
          }
        }
      };
    </script>
    <style lang="stylus" rel="stylesheet/stylus">
      @import 'activitysList.styl';
    </style>
    
    //mvList.vue
    <template>
      <ul class="MV-area">
        <li class="mv-card-find" v-for="(data, index) in MVs" style="flex: 0 0 49.5%" @click="jumpMvDetail(data.id)" :key="index">
          <img v-lazy="data.picUrl + '?param=400y200'" lazy="loading">
          <h2 style="-webkit-box-orient: vertical;">{{data.name}}</h2>
        </li>
      </ul>
    </template>
    <script>
      export default {
        name: 'v-mv-list',
        props: {
          MVs: {
            type: Array,
            default: []
          }
        },
        methods: {
          jumpMvDetail(id) {
            this.$router.push({
              path: '/mv/' + id
            });
          }
        }
      };
    </script>
    
    
    //newSongList.vue
    <template>
      <ul class="newSongList-area">
        <li class="newSongList-card-find" v-for="(data, index) in newSong" @click="jumpAlbumDetail(data.song.album.id)" :key="index">
          <img v-lazy="data.song.album.picUrl+ '?param=200y200'" lazy="loading">
          <h2 style="-webkit-box-orient: vertical;-webkit-line-clamp: 1">{{data.name}}</h2>
          <p style="-webkit-box-orient: vertical;">{{data.song.artists[0].name}}</p>
        </li>
      </ul>
    </template>
    <script>
      export default {
        name: 'v-new-song-lists',
        props: {
          newSong: {
            type: Array,
            default: []
          }
        },
        methods: {
          jumpAlbumDetail(id) {
            this.$router.push({
              path: '/album/' + id
            });
          }
        }
      };
    </script>
    
    
    //djProgram.vue
    <template>
      <ul class="djProgram-area">
        <li class="djProgram-card-find" v-for="(data, index) in djProgram" :key="index">
          <img v-lazy="data.picUrl+ '?param=200y200'" lazy="loading">
          <h2 style="-webkit-box-orient: vertical;">{{data.name}}</h2>
        </li>
      </ul>
    </template>
    <script>
      export default {
        name: 'v-dj-program-lists',
        props: {
          djProgram: {
            type: Array,
            default: []
          }
        },
        methods: {
          jumpPlayListsDetail(id) {
            this.$router.push({
              path: '/playLists/' + id
            });
          }
        }
      };
    </script>
    
    
    //recommend.vue
    <template>
      <div class="recommend-area">
        <div id="slider">
          <swiper :options="swiperOption" style="height: 100%;">
            <swiper-slide v-for="(item, index) in slide_list" :key="index"><img :src="item" class="banner-item"  alt="" style=" 100%; height: 100%;"></swiper-slide>
            <div class="swiper-pagination swiper-pagination-white" slot="pagination"></div>
          </swiper>
        </div>
        <div class="recommend-playLists-area">
          <h1 class="title">推荐歌单</h1>
          <!-- 推荐歌单,有与后端交互 -->
          <v-play-lists :playlists="playlists"></v-play-lists>
        </div>
        <div class="recommend-activitys-area">
          <h1 class="title">独家放送</h1>
          <v-activitys-list :activitys="activitys"></v-activitys-list>
        </div>
        <div class="recommend-mv-area">
          <h1 class="title">最新音乐</h1>
          <v-new-song-list :newSong="newSong"></v-new-song-list>
        </div>
        <div class="recommend-mv-area">
          <h1 class="title">推荐MV</h1>
          <v-mv-list :MVs="MVs"></v-mv-list>
        </div>
        <div class="recommend-mv-area">
          <h1 class="title">主播电台</h1>
          <v-dj-program-list :djProgram="djProgram"></v-dj-program-list>
        </div>
      </div>
    </template>
    <script>
      import api from '../../../api/index';
      import { swiper, swiperSlide } from 'vue-awesome-swiper';
      // v-for
      import vPlayLists from '../../../components/list/find/recommend/playLists';
      // v-for
      import vActivitysList from '../../../components/list/find/recommend/activitysList';
      
      import vMvList from '../../../components/list/find/recommend/mvList';
      import vNewSongList from '../../../components/list/find/recommend/newSongList';
      import vDjProgramList from '../../../components/list/find/recommend/djProgram';
      const imgList = ['/static/banner1.jpg', '/static/banner2.jpg', '/static/banner3.jpg', '/static/banner4.jpg'];
      export default {
        name: 'v-recommend',
        data () {
          return {
            swiperOption: {
              pagination: '.swiper-pagination',
              paginationClickable: true,
              autoplay: 2500
            },
            slide_list: imgList,
            playlists: [],
            activitys: [],
            MVs: [],
            newSong: [],
            djProgram: []
          };
        },
        mounted () {
          this.getPersonalizedResource();
          this.getPrivatecontentResource();
          this.getPersonalizedMvResource();
          this.getNewSongResource();
          this.getDjProgramResource();
        },
        methods: {
          getPersonalizedResource() {
            api.getPersonalized().then((response) => {
              this.playlists = response.data.result;
              console.log('getPersonalizedResource',response);
            })
              .catch((response) => {
                console.log(response);
              });
          },
          getPrivatecontentResource() {
            api.getPrivatecontent().then((response) => {
              this.activitys = response.data.result;
            })
              .catch((response) => {
                console.log(response);
              });
          },
          getPersonalizedMvResource() {
            api.getPersonalizedMv().then((response) => {
              this.MVs = response.data.result;
            })
              .catch((response) => {
                console.log(response);
              });
          },
          getNewSongResource() {
            api.getNewSong().then((response) => {
              this.newSong = response.data.result.slice(0, 6);
            })
              .catch((response) => {
                console.log(response);
              });
          },
          getDjProgramResource() {
            api.getDjProgram().then((response) => {
              this.djProgram = response.data.result.slice(0, 6);
            })
              .catch((response) => {
                console.log(response);
              });
          }
        },
        components: {
          swiper,
          swiperSlide,
          vPlayLists,
          vActivitysList,
          vMvList,
          vNewSongList,
          vDjProgramList
        }
      };
    </script>
    <style lang="stylus" rel="stylesheet/stylus">
      @import 'recommend.styl';
    </style>
    

    //主界面部分代码
    <template>
        <!-- 主界面部分 -->
        <transition name="fade">
            <div class="index">
                <!-- 侧边栏 -->
                <asideMenu v-show="isShowAsideMenu"></asideMenu>
                <!-- 头部 -->
                <v-header></v-header>
                <router-view></router-view>
            </div>
        </transition>
    </template>
    <script>
      import vHeader from '../components/header/header';
      import asideMenu from '../components/aside/aside';
    
      export default {
        computed: {
          isShowAsideMenu() {
            return this.$store.state.isShowAsideMenu;
          }
        },
        components: {
          vHeader,
          asideMenu
        }                                                
      };
    </script>
    <style lang="stylus" rel="stylesheet/stylus" scoped>
        @import 'index.styl';
    </style>
    
    //header.vue
    <template>
      <div class="header">
        <div class="name">
          <span @click="showAsideMenu(true)" class="func"><i class="func-icon"></i></span>
          <router-link to="/find" class="item">
            <span class="music"><i class="music-icon"></i></span>
          </router-link>
          <router-link to="/search" class="item">
            <span class="personal"><i class="personal-icon"></i></span>
          </router-link>
          <span class="search"><i @click="toSearch" class="search-icon"></i></span>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      name: 'header',
      methods: {
        toSearch () {
          this.$router.push('/search');
        },
        showAsideMenu (flag) {
          this.$store.commit('showAsideMenu', flag);
        }
      }
    };
    </script>
    <style lang="stylus" rel="stylesheet/stylus" scoped>
      @import "header.styl";
    </style>
    
    //src/components/aside/aside.vue
    <template>
      <transition name="fadeIn">
        <div  class="aside-menu">
          <i @click="showAsideMenu" class="back"></i>
          <div class="aside">
            <div class="info">
              <img src="https://avatars2.githubusercontent.com/u/16521402?v=3&u=225ef33c491d879294c4cb06621ec15f5b01f02a&s=400">
              <p class="author">浅滩戏虾</p>
            </div>
          </div>
          <div @click.stop.prevent="showAsideMenu" class="mask"></div>
        </div>
      </transition>
    </template>
    <script>
    export default {
      name: 'aside',
      data () {
        return {
          isSignIn: false
        };
      },
      methods: {
        showAsideMenu () {
          this.$store.commit('showAsideMenu', false);
        }
      }
    };
    </script>
    <style lang="stylus" rel="stylesheet/stylus" scoped>
      @import "aside.styl";
    </style>
    
    

    //src/views/find/playLists/playLists.vue
    <template>
      <div class="playLists-area">
        <button-tab v-model="index">
          <button-tab-item @on-item-click="selectType()">最新</button-tab-item>
          <button-tab-item @on-item-click="selectType()">最热</button-tab-item>
        </button-tab>
        <div class="playLists">
          <ul>
            <li v-for="(data, index) in playlists" :key="index">
              <v-play-list :data="data"></v-play-list>
            </li>
          </ul>
        </div>
      </div>
    </template>
    <script>
      import api from '../../../api/index';
      import { ButtonTab, ButtonTabItem } from 'vux';
      import vPlayList from '../../../components/card/findCard/playList/playList';
      export default {
        name: 'v-play-lists',
        data () {
          return {
            index: 0,
            keys: 'new',
            playlists: []
          };
        },
        mounted: function() {
          this.getTopPlaylistResource();
        },
        methods: {
          selectType () {
            this.keys = this.index ? 'hot' : 'new';
            //点击切换,从后端获取数据
            this.getTopPlaylistResource();
          },
          getTopPlaylistResource() {
            this.$store.commit('update_loading', true);
            api.getTopPlaylistResource(this.keys, 20, 0).then((response) => {
              this.playlists = response.data.playlists;
              //数据会先渲染出来,所以要重新渲染完后执行
              // $nextTick() 在dom 重新渲染完后执行
              this.$nextTick(() => {
                this.$store.commit('update_loading', false);
              });
            })
            .catch((response) => {
              console.log(response);
            });
          }
        },
        components: {
          vPlayList,
          ButtonTab,
          ButtonTabItem
        }
      };
    </script>
    <style lang="stylus" rel="stylesheet/stylus" scoped>
      @import 'playLists.styl';
    </style>
    
    //src/components/list/find/ranking/songsList.vue
    <template>
      <ul class="ranking-songsList">
         <li style="-webkit-box-orient: vertical;" v-for="(item, index) in data" :key="index">{{index + 1}}.{{item.name}}-{{item.artists[0].name}}</li>
      </ul>
    </template>
    <script>
      export default {
        name: 'v-songs-list',
        props: {
          data: {
            type: Array,
            default: []
            //如果有和后端交互的数据,页面会展示
          }
        }
      };
    </script>
    <style lang="stylus" rel="stylesheet/stylus">
      @import 'songsList.styl';
    </style>
    

    //search.vue
    <template lang="html">
        <transition name="fade">
            <div class="search-page">
                <div class='header-other'>
                    <span @click="goBack" class="back"><i class="back-icon"></i></span>
                    <div class="input">
                        <input v-model="keywords" @keyup.enter="toSearch(keywords)" type="text" placeholder='搜素音乐、歌手、歌词、用户'>
                        <i @click="keywords=''" v-show="keywords!==''&&!isShowHot" class="icon-cancel"></i>
                    </div>
                </div>
                <div class="hot" v-if="isShowHot">
                    <p>热门搜索</p>
                    <ul class="keywords">
                      <li v-for="item of hotKeywords" v-text="item" @click="toSearch(item)" class="keyword"></li>
                    </ul>
                </div>
                <div v-else class="search-list">
                    <tab :line-width=2 active-color='#b72712' defaultColor='#666' bar-active-color='#b72712'
                         v-model="index">
                        <tab-item class="vux-center" :selected="type === item" v-for="(item, index) in tabList"
                                  @click="type = item" :key="index">{{item}}
                        </tab-item>
                    </tab>
                    <swiper v-model="index" height="100%" :show-dots="false" class="swiper-container">
                        <swiper-item :key="1">
                            <div class="tab-swiper vux-center search-area">
                              <v-single-list :songs="songs"></v-single-list>
                            </div>
                        </swiper-item>
                        <swiper-item :key="2">
                            <div class="tab-swiper vux-center search-area">
                              <v-singer-list :singer="singer"></v-singer-list>
                            </div>
                        </swiper-item>
                        <swiper-item :key="3">
                            <div class="tab-swiper vux-center search-area">
                              <v-album-list :albums="albums"></v-album-list>
                            </div>
                        </swiper-item>
                        <swiper-item :key="4">
                            <div class="tab-swiper vux-center search-area">
                              <v-play-lists :playlist="playlist"></v-play-lists>
                            </div>
                        </swiper-item>
                        <swiper-item :key="5">
                            <div class="tab-swiper vux-center search-area">
                              <v-user-list :user="user"></v-user-list>
                            </div>
                        </swiper-item>
                        <swiper-item :key="6">
                            <div class="tab-swiper vux-center search-area">
                              <v-mv-list :MVs="mvs"></v-mv-list>
                            </div>
                        </swiper-item>
                    </swiper>
                </div>
            </div>
        </transition>
    </template>
    
    <script>
      import api from '../../api/index';
      import { Tab, TabItem, Swiper, SwiperItem } from 'vux';
      import vSingleList from '../../components/list/search/singleList';
      import vSingerList from '../../components/list/search/singerList';
      import vAlbumList from '../../components/list/search/albumList';
      import vPlayLists from '../../components/list/search/playLists';
      import vUserList from '../../components/list/search/userList';
      import vMvList from '../../components/list/search/mvList';
      const list = () => ['单曲', '歌手', '专辑', '歌单', '用户', 'MV'];
      const hotKeywordsList = () => ['清白之年', '我喜欢上你时的内心活动', '我想和你唱',
        'hyukoh', '童话镇', '陈奕迅', '漂洋过海来看你', '许嵩', '成都', '林俊杰'];
      export default {
        name: 'search',
        data () {
          return {
            index: 0,
            tabList: list(),
            hotKeywords: hotKeywordsList(),
            type: '单曲',
            keywords: '',
            isShowHot: true,
            songs: [],
            singer: [],
            albums: [],
            playlist: [],
            user: [],
            mvs: []
          };
        },
        // watch $route 决定是否清除关键词
        watch: {
          '$route' (to, from) {
            if (from.name === 'find') {
                this.keywords = '';
                this.isShowHot = true;
            }
          }
        },
        methods: {
          initSearchList () {
            this.getSingleResource(); //  获取搜索单曲
            this.getAlbumResource(); //  获取搜索专辑
            this.getSingerResource(); //  获取搜索歌手
            this.getPlayListResource(); //  获取搜索歌单
            this.getUserResource(); //  获取搜索用户
            this.getMvResource(); // 获取搜索MV
          },
          goBack () {
            //返回
            this.$router.push({
              path: '/find'
            });
          },
          // 关键词搜索
          toSearch (keywords) {
            //关键词搜索
            this.keywords = keywords;
            if (this.keywords.trim()) {
              this.isShowHot = false;
              this.$router.push({
                path: '/search',
                query: {
                  keywords: keywords
                }
              });
              this.initSearchList();
            }
          },
          //  获取搜索单曲
          getSingleResource() {
            this.$store.commit('update_loading', true);
            //获取搜索单曲
            api.getSearchResource(this.$route.query.keywords, 1, 30, 0)
              .then((response) => {
                this.songs = response.data.result.songs;
                // $nextTick() 在dom 重新渲染完后执行
                this.$nextTick(() => {
                  this.$store.commit('update_loading', false);
                });
              })
              .catch((response) => {
                console.log(response);
              });
          },
          //  获取搜索专辑
          getSingerResource() {
            //与后端交互
            api.getSearchResource(this.$route.query.keywords, 100, 30, 0)
              .then((response) => {
                this.singer = response.data.result.artists;
              })
              .catch((response) => {
                console.log(response);
              });
          },
          //  获取搜索歌手
          getAlbumResource() {
            api.getSearchResource(this.$route.query.keywords, 10, 30, 0)
              .then((response) => {
                this.albums = response.data.result.albums;
              })
              .catch((response) => {
                console.log(response);
              });
          },
          //  获取搜索歌单
          getPlayListResource() {
            api.getSearchResource(this.$route.query.keywords, 1000, 30, 0)
              .then((response) => {
                this.playlist = response.data.result.playlists;
              })
              .catch((response) => {
                console.log(response);
              });
          },
          //  获取搜索用户
          getUserResource() {
            api.getSearchResource(this.$route.query.keywords, 1002, 30, 0)
              .then((response) => {
                this.user = response.data.result.userprofiles;
              })
              .catch((response) => {
                console.log(response);
              });
          },
          //  获取搜索MV
          getMvResource() {
            api.getSearchResource(this.$route.query.keywords, 1004, 30, 0)
              .then((response) => {
                this.mvs = response.data.result.mvs;
              })
              .catch((response) => {
                console.log(response);
              });
          }
        },
        components: {
          Tab,
          TabItem,
          Swiper,
          SwiperItem,
          vSingleList,
          vSingerList,
          vAlbumList,
          vPlayLists,
          vUserList,
          vMvList
        }
      };
    </script>
    <style lang="stylus" rel="stylesheet/stylus" scoped>
        @import "search.styl";
    </style>
    

    //singerList.vue
    <template>
      <ul class="singer-list">
        <li class="singer-card"  v-for="(data, index) in singer" @click="jumpSingerDetail(data.id)" :key="index">
          <img v-lazy="data.picUrl + '?param=200y200'" lazy="loading" class="avatar">
          <p class="singer-name">
            <span class="name" style="-webkit-box-orient: vertical;">{{data.name}}</span>
            <span class="trans" v-show="data.trans">({{data.trans}})</span>
          </p>
        </li>
      </ul>
    </template>
    <script>
      export default {
        name: 'v-singer-list',
        props: {
          singer: {
            type: Array,
            default: []
          }
        },
        methods: {
          jumpSingerDetail(id) {
            this.$router.push({
              path: '/singer/' + id
            });
          }
        }
      };
    </script>
    <style lang="stylus" rel="stylesheet/stylus" scoped>
      @import 'singerList.styl';
    </style>
    
    //albumList.vue
    <template>
      <ul class="album-list">
        <v-album-card :data="data" v-for="(data, index) in albums" :key="index"></v-album-card>
      </ul>
    </template>
    <script>
    import vAlbumCard from '../../card/searchCard/albumCard';
      export default {
        name: 'v-album-list',
        components: {
          vAlbumCard
        },
        props: {
          albums: {
            type: Array,
            default: []
          }
        }
      };
    </script>
    <style lang="stylus" rel="stylesheet/stylus" scoped>
      @import 'albumList.styl';
    </style>
    
    //userList.vue
    <template>
        <ul class="user-list">
          <li v-for="(data, index) in user" class="user-card" @click="jumpUserDetail(data.userId)" :key="index">
            <img v-lazy="data.avatarUrl + '?param=200y200'" lazy="loading" class="avatarImage">
            <div class="avatar-info">
                <p class="avatar-name">
                    {{data.nickname}}
                    <span class="gender-man" v-if="data.gender === 1"><i class="man-icon"></i></span>
                    <span class="gender-female" v-else><i class="female-icon"></i></span>
                </p>
                <p class="avatar-intro" style="-webkit-box-orient: vertical;">{{data.signature}}</p>
            </div>
          </li>
        </ul>
    </template>
    <!-- v-if v-else的使用 -->
    <script>
      export default {
        name: 'v-user-card',
        props: {
          user: {
            type: Array,
            default: []
          }
        },
        methods: {
          jumpUserDetail(id) {
            this.$router.push({
              path: '/user/' + id
            });
          }
        }
      };
    </script>
    <style lang="stylus" rel="stylesheet/stylus" scoped>
        @import 'userList.styl';
    </style>
    
    //mvList.vue
    <template>
      <ul class="mv-list">
        <li class="mv-card" v-for="(data, index) in MVs" style="flex: 0 0 49.5%" @click="jumpMvDetail(data.id)" :key="index">
          <img v-lazy="data.cover + '?param=400y200'" lazy="loading" class="mv-image">
          <h2 style="-webkit-box-orient: vertical;">{{data.name}}</h2>
          <p style="-webkit-box-orient: vertical;">{{data.artistName}}</p>
        </li>
      </ul>
    </template>
    <script>
      export default {
        name: 'v-mv-list',
        props: {
          MVs: {
            type: Array,
            default: []
          }
        },
        methods: {
          jumpMvDetail(id) {
            this.$router.push({
              path: '/mv/' + id
            });
          }
        }
      };
    </script>
    <style lang="stylus" rel="stylesheet/stylus" scoped>
      @import 'mvList.styl';
    </style>
    

    //user.vue
    <template>
      <transition name="fade">
        <div class="user-detail">
          <div class="user-info" :style="{'background-image': 'url(' + backgroundImage + ')'}">
            <x-header :left-options="{backText: ''}" style="background-color:inherit;  100%;">{{userInfo.nickname}}</x-header>
            <img v-lazy="avatarImage + '?param=200y200'" lazy="loading">
            <p class="user-name">
              {{userInfo.nickname}}
              <span class="gender-man" v-if="userInfo.gender === 1"><i class="man-icon"></i></span>
              <span class="gender-female" v-else><i class="female-icon"></i></span>
            </p>
          </div>
          <div class="tab-list">
            <tab :line-width=2 active-color='#b72712' defaultColor='#666' bar-active-color='#b72712' v-model="index">
              <tab-item class="vux-center" :selected="type === item" v-for="(item, index) in tabList" @click="type = item" :key="index">{{item}}</tab-item>
            </tab>
            <swiper v-model="index" height="100%" :show-dots="false">
              <swiper-item :key="0">
              <div class="tab-swiper vux-center">
                <div class="play-lists-detail">
                  <ul style="list-style: none;">
                    <li v-for="(data, index) in playlist" :key="index">
                      <v-play-lists-card :data="data"></v-play-lists-card>
                    </li>
                  </ul>
                </div>
              </div>
              </swiper-item>
              <swiper-item :key="1">
                <!--<div class="tab-swiper vux-center">-->
                <!--<div class="hot-single-list">-->
                <!--<ul>-->
                <!--<li v-for="(data, order) in playlist">-->
                <!--<v-single-card :data="data" :order="order"></v-single-card>-->
                <!--</li>-->
                <!--</ul>-->
                <!--</div>-->
                <!--</div>-->
              </swiper-item>
            </swiper>
          </div>
        </div>
      </transition>
    </template>
    <script type="text/ecmascript-6">
      import api from '../../../api';
      import { XHeader, Tab, TabItem, Swiper, SwiperItem } from 'vux';
      import vPlayListsCard from '../../../components/card/detail/playlists';
      const list = () => ['歌单', '关于TA'];
      export default {
        data () {
          return {
            tName: '歌单',
            type: '歌单',
            tabList: list(),
            index: 0,
            backgroundColor: '',
            userInfo: {},
            playlist: {}
          };
        },
        mounted: function() {
          this.getUserInfo();
        },
        methods: {
          back () {
            this.$router.go(-1);
          },
          getUserInfo () {
            this.$store.commit('update_loading', true);
            //与后端交互获取资源
            api.getUserPlaylistResource(this.$route.params.id)
              .then((response) => {
                this.playlist = response.data.playlist;
                this.userInfo = response.data.playlist[0].creator;
                // $nextTick() 在dom 重新渲染完后执行
                this.$nextTick(() => {
                  this.$store.commit('update_loading', false);
                });
              })
              .catch((response) => {
                console.log(response);
              });
          }
        },
        computed: {
          backgroundImage() {
            return '' || (this.userInfo.backgroundUrl + '?param=500y500');
          },
          avatarImage() {
            return '' || this.userInfo.avatarUrl;
          }
        },
        components: {
          Tab,
          TabItem,
          Swiper,
          SwiperItem,
          XHeader,
          vPlayListsCard
        }
      };
    </script>
    <style lang="less" scoped>
      .vux-swiper {
        height: 100%;
      }
    
      .vux-slider {
        height: 100%;
      }
    
      .tab-swiper {
        background-color: #fff;
        height: 100%;
      }
    </style>
    <style lang="stylus" rel="stylesheet/stylus">
      @import "user.styl";
    </style>
    
    //playlists.vue
    <template>
      <transition name="fade">
        <div class="playlist">
          <div class="fixed-title" :style="{'background': 'rgba(183, 39, 18, '+ opacity +')'}" style="transition: opacity .1s;" v-show="!isShowDetail">
            <x-header :left-options="{backText: ''}" style="background-color:transparent">{{tName}}</x-header>
          </div>
          <div class="playlist-info" :style="{'background-image': 'url(' + playListImage + '?param=500y500'+ ')'}" v-show="!isShowDetail">
            <div class="playlist-info-blur">
                <div class="playlist-intro">
                  <img v-lazy="playListImage" class="playlist-image" lazy="loading" alt="photo" @click="showDetail()">
                  <div class="playlist-intro-other">
                    <p class="playlist-title" style="-webkit-box-orient: vertical;">{{playlist.name}}</p>
                    <div class="playlist-creator" @click="jumpUserDetail(creator.userId)">
                      <img v-lazy="creatorImage + '?param=100y100'" lazy="loading">
                      <span class="playlist-nickname" style="-webkit-box-orient: vertical;">{{creator.nickname}}</span>
                      <span class="more"> > </span>
                    </div>
                  </div>
                </div>
                <div class="playlist-status">
                  <div class="playCount">
                    <span class="file"><i class="icon-file"></i></span>
                    <span>{{playlist.playCount}}</span>
                  </div>
                  <div class="commentCount">
                    <span class="comment" @click="jumpCommentDetail()"><i class="icon-comment"></i></span>
                    <span>{{playlist.commentCount}}</span>
                  </div>
                  <div class="shareCount">
                    <span class="share"><i class="icon-share"></i></span>
                    <span>{{playlist.shareCount}}</span>
                  </div>
                </div>
            </div>
          </div>
          <div class="play-list" v-show="!isShowDetail">
              <v-play-all :data="commonSongs"></v-play-all>
              <ul>
                <li v-for="(data, index) in list" :key='index'>
                    <v-single-card :data="data" :index="index"></v-single-card>
                </li>
              </ul>
          </div>
          <v-play-list-detail :data="playlist" v-show="isShowDetail"></v-play-list-detail>
        </div>
      </transition>
    </template>
    <script>
      import api from '../../../api';
      import { XHeader } from 'vux';
      import vPlayAll from '../../../components/playAll/playAll.vue';
      import vSingleCard from '../../../components/card/detail/singleCard.vue';
      import vPlayListDetail from './playListDetail';
      export default {
        data () {
          return {
            playlist: {},
            tName: '歌单',
            creator: {},
            data: [],
            index: '',
            list: [],
            commonSongs: [],
            backgroundColor: '',
            opacity: 0,
            isShowDetail: false
          };
        },
        // 解除keep-alive的缓存
        beforeRouteEnter: (to, from, next) => {
          next(vm => {
            window.onscroll = () => {
              let opa = window.pageYOffset / 222;
              if (opa > 1) {
                  vm.tName = vm.playlist.name;
                  vm.opacity = 1;
              } else {
                  vm.tName = '歌单';
                  vm.opacity = 0;
              }
            };
          });
        },
        // 路由离开时清除onscroll事件
        beforeRouteLeave: (to, from, next) => {
          window.onscroll = null;
          next();
        },
        mounted: function() {
          let self = this;
          this.getPlayListDetail();
          this.$root.$on('close-detail', (condition) => {
            self.isShowDetail = condition;
          });
        },
        methods: {
          showDetail () {
            this.isShowDetail = true;
          },
          jumpUserDetail(id) {
            this.$router.push({
              path: '/user/' + id
            });
          },
          jumpCommentDetail() {
            this.$router.push({
              path: '/playListComment/' + this.$route.params.id
            });
          },
          getPlayListDetail () {
            //与后端交互获取数据
            this.$store.commit('update_loading', true);
            api.getPlaylistDetailResource(this.$route.params.id).then((response) => {
              this.playlist = response.data.playlist;
              this.list = response.data.playlist.tracks;
              this.creator = response.data.playlist.creator;
              this.songsToCommon(this.list);
              // $nextTick() 在dom 重新渲染完后执行
              this.$nextTick(() => {
                this.$store.commit('update_loading', false);
              });
            }).catch((error) => {
              console.log('加载歌单信息出错:' + error);
            });
          },
          songsToCommon (items) {
            let vm = this;
            this.commonSongs = items.map(function (item) {
              return {
                'id': item.id,
                'name': item.name,
                'singer': vm.getAuthorList(item.ar),
                'albumPic': item.al.picUrl,
                'location': '',
                'album': item.al.id
              };
            });
          },
          getAuthorList(authorInfo) {
            return authorInfo.map(function (item) {
              return item.name;
            }).toString();
          }
        },
        computed: {
          playListImage() {
            return '' || (this.playlist.picUrl);
          },
          creatorImage() {
            return '' || this.creator.avatarUrl;
          }
        },
        components: {
          XHeader,
          vPlayAll,
          vSingleCard,
          vPlayListDetail
        }
      };
    </script>
    <style lang="stylus" rel="stylesheet/stylus" scoped>
      @import "playlists.styl";
    </style>
    

    本文学习自这位非常美丽的小姐姐,表白你哇

  • 相关阅读:
    NOJ 1116 哈罗哈的大披萨 【淡蓝】 [状压dp+各种优化]
    Codeforces Round #278 (Div. 2) B. Candy Boxes [brute force+constructive algorithms]
    noj 2069 赵信的往事 [yy题 无限gcd]
    noj 2068 爱魔法的露露 [线性扫一遍]
    Codeforces Round #275 (Div. 2) B. Friends and Presents 二分+数学
    Word2007文档中怎么输入上标下标
    Linux下查找命令
    矩阵求逆
    LRC算法在人脸识别中应用
    java从txt文档读写数据
  • 原文地址:https://www.cnblogs.com/smart-girl/p/10817227.html
Copyright © 2011-2022 走看看