要使用vuex首先得安裝然后引入,在項目的src目錄下建立store文件夾,分別新建state,js,mutation.js,index.js.getter.js,actions.js
state.js,存儲了組件之間需要共享的變量:
import {
playMode
} from '@/utils/config.js'
const state = {
// 歌手信息:
singer: {},
// 是否正在播放音樂
playing: false,
// 播放器展開或者收起:
fullScreen: false,
// 播放的列表:
playList: [],
// 順序列表
sequenceList: [],
// 播放模式:
mode: playMode.sequence,
// 當前播放歌曲的索引:
currentIndex: -1
}
export default state
其中播放模式可以從外部引用,方便語義化的管理 config.js:
// 配置文件:
// 播放模式:
export const playMode = {
// 順序播放:
sequence: 0,
// 循環播放:
loop: 0,
// 隨機播放:
random: 2
}
mutations.js定義了修改state的方法
const matutaions = {
SET_SINGER(state, singer) {
state.singer = singer
},
SET_PLAYING_STATE(state, flag) {
state.playing = flag
},
SET_FULL_SCREEN(state, flag) {
state.fullScreen = flag
},
SET_PLAYLIST(state, list) {
state.playList = list
},
SET_SEQUENCE_LIST(state, list) {
state.sequenceList = list
},
SET_PLAY_MODE(state, mode) {
state.mode = mode
},
SET_CURRENT_INDEX(state, index) {
state.currentIndex = index
}
}
export default matutaions
getters.js類似於組件中computed,可以對mutations的數據再處理,也可以直接拿到state的數據
// 重新包裝一下方便直接從組件中拿到數據
export const singer = state => state.singer
export const playing = state => state.playing
export const fullScreen = state => state.fullScreen
export const playList = state => state.playList
export const sequenceList = state => state.sequenceList
export const mode = state => state.mode
export const currentIndex = state => state.currentIndex
// 獲取當前播放歌曲
export const currentSong = (state) => {
return state.playList[state.currentIndex] || {}
}
actions可以同時提交多個mutations,一些異步方法也可以在這里使用
// 同時操縱多個mutation可以使用actions;
// 封裝多個mutations:
export const selectPlay = function ({
commit,
state
}, {
list,
index
}) {
console.log(state);
commit('SET_SEQUENCE_LIST', list)
commit('SET_PLAYLIST', list)
commit('SET_CURRENT_INDEX', index)
commit('SET_FULL_SCREEN', true)
commit('SET_PLAYING_STATE', true)
}
在歌手列表頁點擊歌手之后需要跳轉到歌手詳情,同時需要把歌手信息傳遞進去,方法一可以用參數傳遞的方式,方法二傳遞歌手ID直接再歌手詳情頁面,重新獲取數據,方法三可以直接使用 vuex
在這里使用vuex,因為要改變state,所以引入 mapMutations,
先引入mapMutations
import { mapMutations } from "vuex";
methods中展開mutations,SET_SINGER為mutations中的方法名
...mapMutations({
setSinger: "SET_SINGER"
})
點擊事件傳遞item給mutation
this.setSinger(item); 傳遞item
Todetail(item) {
// console.log(item);
this.$router.push({
path: `/singer/${item.id}`
});
// 實際調用了this.$store.commit('setSinger',item)....
this.setSinger(item);
},
歌手詳情頁的頭部需要用到vuex中保存的歌手信息

在singer-detail組件中的computed方法中定義getters:
import { mapGetters } from "vuex";
...mapGetters(["singer"]),
title() {
return this.singer.name;
},
bgImage() {
return this.singer.avatar;
}
因為這個音樂列表在其他歌單列表也會用到,所以抽象成組件,把參數作為props傳遞進去
前面因為傳遞了歌手id,所以可以根據這個id去獲取該歌手的top50首歌
const { artist, hotSongs } = await getSingerMusic(this.singer.id);
// 歌手信息
this.artistInfo = artist;
// 熱門歌曲
this.hotSongs = hotSongs;
解構出的artist保存着歌手更全的信息



這同樣是沒法用的,所以也需要一個格式化函數獲取需要的數據
需要的是歌曲id,歌單id,唱這首歌的全部歌手,姓名(主唱),專輯,播放時長,圖片
在common文件夾中新建一個song.js
歌曲的播放地址需要通過id發送請求再獲得
//獲取歌曲播放地址 export const getsongUrl = p => get(`/song/url`, p)
song.js中引入
import {
getsongUrl,
} from "@/request/api.js";
歌手可能有多個所以准備一個轉換函數把數組轉換成‘/’分割的字符串
function filterSinger(singer) {
let ret = [];
if (!singer) {
return ''
}
singer.forEach((s) => {
ret.push(s.name)
})
return ret.join('/')
}
定義一個構造函數
export default class Song {
constructor({
id,
mid,
singer,
name,
album,
duration,
image,
}) {
this.id = id;
this.mid = mid;
this.singer = singer;
this.name = name;
this.album = album;
this.duration = duration;
this.image = image;
getsongUrl({
id: this.id
}).then(res => {
// console.log(res.data[0]);
this.url = res.data[0].url
})
}
}
導出一個歌曲生成的構造函數,參數是全部數據的data,根據參數返回需要的結果
export function createSong(musicData) {
return new Song({
id: musicData.id,
mid: musicData.al.id,
singer: filterSinger(musicData.ar),
duration: musicData.duration ? musicData.duration : musicData.dt ? musicData.dt : '',
name: musicData.name,
album: musicData.al.name,
image: musicData.al.picUrl + '?param=300y300',
url: musicData.id
})
}
回到singer-detail,引入這個函數
import { createSong } from "@/common/song";
定義格式化函數,在執行函數時確保id存在
_normalizeSongs(list) {
let ret = [];
list.forEach(item => {
// console.log(item);
if (item.id && item.al.id) {
ret.push(createSong(item));
}
});
return ret;
}
使用該函數
// 熱門歌曲
this.songs = this._normalizeSongs(hotSongs);
console.log(this.songs);
可以看到那50首歌都格式化好了

最后把數據給子組件就好了
<music-list :songs="songs" :bg-image="bgImage" :title="title"></music-list>

