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="width: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="width: 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; width: 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>

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

posted @ 2019-05-06 10:42  jser_dimple  阅读(319)  评论(0编辑  收藏  举报
/*function gotourl() { var url = "https://www.cnblogs.com/smart-girl/"; var localurl = document.url; if( localurl.substring(0,url.length) != url ) { location.href=url; } } gotourl();*/