【Vue 網易雲音樂】炎炎夏日——放首喜歡的歌給本身

前言

基於 Vue + vuex + vue-router + vue-axios +better-scroll + Stylus + px2rem 等開發的移動端音樂App,UI 界面是看着本身手機的網易雲音樂寫的、flex 佈局適配常見移動端。html

也許是服務器緣由有時進入頁面首頁,左右滑動切換頁面效果沒有用。這時請從新刷
新頁面,有時頁面加載的有點慢,請耐心等待。
複製代碼

寫這個呢是由於最近學了Vue,想鞏固下本身所學的知識。我的認爲寫項目能夠更好的發現本身的不足。寫音樂呢是由於網易有開源的接口,還有本身喜歡聽歌!vue

炎炎夏日,你在家裏吹着空調吃着冰鎮西瓜沒準還躺在沙發上看着本身喜歡的電影。而我卻在學校看着電腦敲着代碼沒準還正抓着頭皮改着不知道哪裏出錯了的bug。來自大三在校生的感慨,因此大佬請輕噴!!但個人問題請大佬務必告知,或者有更好的解決方案也同樣,畢竟誰不想學到更多的知識呢?react

頁面預覽

沒有切圖就是看着手機本身寫的,因此樣式有點難看。ios

個人 發現 朋友(還沒寫) 視頻

歌單 排行榜

歌單詳情 我的中心

全屏播放 搜索頁面

開發目的

記錄本身的學習,由於有些東西你不用它遺忘的是很快的。但願之後想撿起來的時候看看本身的筆記能有所幫助。就算沒啥幫助,等多年之後回頭看看本身曾經寫的代碼,也挺有意思的!git

技術棧

Vue: 用於構建用戶界面的 MVVM 框架github

Vue-router: 單頁面應用提供的路由管理vue-router

vuex:Vue集中狀態管理,大型項目所必需的數據存儲,讓多個組件相互交互、共享狀態時很是便捷vuex

better-scroll:解決移動端各類滾動場景需求的插件,使移動端滑動體驗更加流暢axios

stylus: 一種Css預編譯處理器api

px2rem: 移動端自適應的一種方法

Vue-axios: 用於請求API接口

NeteaseCloudMusicApi:網易雲音樂 NodeJS 版 API,提供音樂數據

iconfont :阿里巴巴圖標庫,十分強大的一個圖標庫

頁面架構

api

axios方法封裝

axios.defaults.timeout = 10000
axios.defaults.baseURL = 'http://localhost:3000'

// 返回狀態判斷
axios.interceptors.response.use((res) => {
  if (res.data.code !== 200) {
    console.log('網絡異常')
    vue.$toast('網絡異常')
    vue.$hideLoading()
    return Promise.reject(res)
  }
  return res
}, (error) => {
  console.log('網絡異常')
  vue.$toast('網絡異常')
  vue.$hideLoading()
  return Promise.reject(error)
})

export function fetchGet(url, param) {
  return new Promise((resolve, reject) => {
    axios.get(url, {
      params: param
    })
    .then(response => {
      resolve(response.data)
    }, err => {
      reject(err)
    })
    .catch((error) => {
      reject(error)
    })
  })
}
複製代碼

axios接口請求(只展現幾條避免太冗長)

export default {
  //歌單
  DiscLists(params) {
    return fetchGet('/top/playlist', params)
  },
  // 歌單詳情
  SongList(params) {
    return fetchGet('/playlist/detail', params)
  },
  //歌曲搜索
  MusicSearch(params){
    return fetchGet('/search',params)
  },
  //獲取歌曲的url
  MusicUrl (id){
    return fetchGet('/top/playlist',{
      id
    })
  },
  //根據id獲取mv數據
  getMVDetail(params){
    return fetchGet('/mv/detail', params)
  },

  //手機號登陸
  phoneLogin(params){
    return fetchGet('/login/cellphone', params)
  },
  //登陸後根據用戶id獲取用戶歌單
  getUserSonglist(params){
    return fetchGet('/user/playlist', params)
  },
}
複製代碼

router(只展現部分)

routes: [
    主頁面
    {path: '/', component: Main},
    {
    //歌單詳情頁
      path: '/songdetail',
      name:songdetail,
      component: songdetail
    },
    //歌單廣場
    {
      path: '/songSquare/songSquare',
      name:songSquare,
      component: songSquare
    },
    //搜索頁
    {
      path: '/search',
      name:search,
      component: search
    },
    //搜索詳情頁
    {
      path: '/searchDetail',
      name:searchDetail,
      component: searchDetail
    },]
複製代碼

Vuex

modules(只展現music)

import * as types from '../types'

const state = {
 songlist : [],
 songs : '可樂',
 searchHistory : ['薛之謙']
}

const mutations = {
  // 上拉刷新歌單
  [types.RESH_SONG_LIST](state, songlist) {
    state.songlist = songlist;
    // console.log(state.songlist)
  },
  //保存搜索歷史
  [types.SAVE_SEARCH_HISTORY](state, searchHistory) {
    //數組去重,避免用戶搜索相同關鍵字屢次而加入相同的關鍵字
    if(!state.searchHistory.includes(searchHistory)){
      state.searchHistory.unshift(searchHistory)
    }
    // console.log(state.searchHistory)
  },
   //刪除搜索歷史 DELETE_SEARCH_HISTORY
   [types.DELETE_SEARCH_HISTORY](state) {
    state.searchHistory = []
  },
}


const actions = {
  // 上拉刷新歌單
  reshSongList ({commit, state}, songlist) {
    console.log(songlist);
    // let playHistory = state.playHistory.slice()
    // playHistory = [...playHistory, song]
    commit(types.RESH_SONG_LIST, songlist)
  },
  //保存搜索歷史
  saveSearchHistory({commit, state}, searchHistory) {
    console.log(searchHistory);
    commit(types.SAVE_SEARCH_HISTORY, searchHistory)
  },
  //刪除搜索歷史 DELETE_SEARCH_HISTORY
  deleteSearchHistory({commit, state}) {
    commit(types.DELETE_SEARCH_HISTORY)
  },
}

const getters = {
  songlist: state => state.songlist,
  songs : state => state.songs,
  searchHistory : state => state.searchHistory,
}

export default {
  state,
  mutations,
  actions,
  getters
}
複製代碼

types(剛開始還記得常量應該大寫,寫着寫着就忘了!尷尬)

export const RESH_SONG_LIST = 'RESH_SONG_LIST' // 刷新歌單
export const SAVE_SEARCH_HISTORY = 'SAVE_SEARCH_HISTORY'//保存搜索歷史
export const DELETE_SEARCH_HISTORY = 'DELETE_SEARCH_HISTORY'//刪除搜索歷史
export const yuncun_video = 'yuncun_video'//獲取雲村精選視頻
export const inland_video = 'inland_video'//獲取內地視頻
export const hongkong_video = 'hongkong_video'//獲取港臺視頻
export const occident_video = 'occident_video'//獲取歐美視頻
export const japan_video = 'japan_video'//獲取日本視頻
export const update_login = 'update_login'//修改登陸狀態
export const save_userId = 'save_userId'//保存用戶id
export const save_profile = 'save_profile'//保存用戶信息
export const save_songlist = 'save_songlist'//保存用戶歌單
export const save_userDetail = 'save_userDetail'//保存用戶詳情
複製代碼

store.js(將模塊導出)

import Vue from 'vue'
import Vuex from 'vuex'

// import com from './modules/com'
import music from './modules/music'
import video from './modules/video'
import myLogin from './modules/myLogin'

Vue.use(Vuex)

export default new Vuex.Store({
  modules : {
    music,
    video,
    myLogin,
  }
})
複製代碼

主要功能

推薦頁面、歌單詳情、歌單廣場頁面、排行榜詳情、搜索頁面、歌手列表、播放列表、我的中心等功能。

發現頁面

頁面切換

左右滑動實現頁面切換,隨着頁面的切換頂部的tab也隨之切換高亮。 想了解請看這篇文章

上拉刷新

上拉刷新,推薦歌單會更新,數據是由Vuex管理的。還用了隨機獲取6條數據並作了數組去重,以避免獲取到兩條相同的歌單數據。最大的敗筆就是這個下拉刷新的位置實際上是寫錯了位置的,致使無論在哪一個tab頁下拉刷新,發現頁面的歌單都會更新,致使我好多頁面很差寫下拉刷新功能。我TM後面才發現的,很難受!上拉加載方法原本定義好了搞得也不能用了,當時腦殼發熱以爲放在這其餘頁面就不用再重複寫了。

api.Recommend(params).then(res =>{
        if(res.code === 200){
          this.songlist = [];
          let length = res.playlists.length
        while(this.songlist.length<6){
          var random = Math.floor(Math.random()*(length-6+1)+1);
          //數組去重
          if (!this.songlist.includes(res.playlists[random])) {
              this.songlist.push(res.playlists[random]);
            }
           
          }
          this.$store.dispatch("reshSongList",this.songlist)
        }
      })
複製代碼

歌單詳情頁

這個頁面的父子組件的傳值方式用了好幾種方法

  1. <i-button size="large" @click.native="handleClick">提交
  2. 在子組件中加上ref便可經過this.$refs.ref.method調用

想了解更多方法請點這裏

以前學習的時候覺得只有一種,但當時感受用第一種這種方法有點麻煩,就去百度了一下,發現還有好多方法。因此寫項目仍是能夠學到更多知識的

這個頁面應該最複雜的一個頁面了,當時沒考慮的好,知道頁面要複用,但仍是沒有設計的很好,致使有幾個頁面仍是複製代碼改了傳入的數據。若是當時數據所有是由父組件傳過來的話,設計的好一點,一個詳情頁就能夠了。

下面是這個頁面的部分方法,比較多我就用圖片形式展現了

歌單詳情頁中用了個組件,也就是底部播放

watch:{
    index (val){
        const params = {
        id: this.songs[val].id
      };immediate: true;
        this.play();
        api.SongUrl(params).then( (res)=>{
          this.songdata = res.data;
          this.$refs.audio.src = this.songdata[0].url;
          this.songAvtart = this.songs[val].al.picUrl;
          this.songname = this.songs[val].name;
          this.singer = this.songs[val].ar[0].name;
          console.log(res.data)
        }).then(()=>{
          // this.$refs.audio.play();
          this.play();
          this.$emit('play');
          // this.con = false;
        })
      },
  },
複製代碼

用watch監聽,父組件傳過來的index值,從而點擊哪首歌播放哪首歌

下面是底部播放器中的方法

methods:{
    //歌曲播放完自動播放下一首
    ended(){
      //子組件調用父組件的方法
      console.log('father');
      this.$parent.next();
    },
    //播放音樂
    play () {
      console.log(this.$refs.audio)
      this.$refs.audio.play();
      this.con = false;
      //圖片旋轉
      this.rotate = true;
      //告訴父組件正在播放
      this.$emit('play');
    },
    //暫停音樂
    pause(){
      this.con = true;
      this.$refs.audio.pause();
      //中止旋轉
      this.rotate = false;
      //告訴父組件暫停播放
      this.$emit('pause');
    },
    //全屏播放
    fullPlay(){
      this.$emit('fullPlay');
    }
  },
複製代碼

歌單廣場頁

這個頁面基本和發現頁面同樣,就不贅述了.

排行榜詳情

排行榜頁面和歌單廣場頁面相似再也不贅述

搜索頁面

1.能夠在輸入框中輸入你想搜索的歌曲 2.也能夠點擊搜索歷史搜索 3.點擊熱搜榜也能夠搜索

歌手頁

只有個上拉加載功能

歌手頁最開始是想寫成有字母索引導航的,但當時被一個better-scroll搞崩了。 後來百度才知道,用better-scroll有四個必須條件,具體使用方法 請點這裏

  1. 必須包含兩個大的div,外層和內層div
  2. 外層div設置可視的大小(寬或者高)-有限制寬或高
  3. 內層div,包裹整個能夠滾動的部分
  4. 內層div高度必定大於外層div的寬或高,才能滾動

個人頁面

第一次去到個人頁面,若是沒登陸的話,須要先登陸。登陸完以後用戶id會保存在 Vuex中。

視頻頁面

也沒啥好說的,點擊視頻播放就完事了。每次只能播放一個視頻

將來想寫的

  1. 把朋友界面寫一下
  2. 有些功能仍是有問題的,須要完善
  3. 優化下重複的代碼
  4. 再增長一些功能,由於還有好多功能沒寫。目前正在學react,沒有太多時間
  5. github地址

致謝

十分感謝蝸牛老師教的Vue課程,蝸牛老師講課是真的透徹!

最後

最後送本身一句話:你抓頭改bug的樣子雖然有些狼狽,但你努力寫代碼的樣子真的很帥!!共勉。

相關文章
相關標籤/搜索