vue中使用vuex管理各种状态
要使用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>