在事件总线的例子中,我们实现了进入detail页面不显示下面的tabbar,在离开detail页面中,显示tabbar这样的效果。我们使用的是事件总线的事件订阅机制。
在这个例子中,我们用VueX状态管理来更好的实现一下这样的功能。
1.编写VueX状态管理文件
//===>src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
//自定义的共享状态
isTabbarShow: true
},
mutations: {
HideMaizuoTabbar(state, data) {
state.isTabbarShow = data
}
},
actions: {
},
modules: {
}
})
2.来看一下src/main.js
在这个文件中,store是之前为我们定义好的。程序加载之后,store就在全局挂载了,所以我们就可以直接去使用它
//===>src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
3.重写Detail的beforeMount()和beforeDestroy()方法,修改状态。
...
beforeMount() {
// bus.$emit("maizuo", false);
this.$store.commit("HideMaizuoTabbar", false);
}
...
beforeDestroy() {
// bus.$emit("maizuo", true);
this.$store.commit("HideMaizuoTabbar", true);
}
...
为了更好的观察store的变化,保护状态不被随便改动。我们不能直接修改store中的state。所以,我们要使用mutations帮我们修改。
在第三步我们修改beforeMount()方法的时候,我们使用了this.$store.commit("HideMaizuoTabbar", false);这样的方法,HideMaizuoTabbar会找到我们在第一步mutations中定义好的同名方法,然后通过参数去修改state中的isTabbarShow
devtools
使用mutations修改数据的好处是,我们可以在devtools插件中观察到state的数据变化。
image.png
异步
我们想实现,在正在热映和即将上映之间切换的时候,如果有缓存数据,就直接用缓存数据,这该怎么弄呢?
实现原理:
判断store中有没有nowplaying数据。没有->ajax(action->mutation->state);有->直接从store取数据,渲染页面
1.首先编写Comingsoon.vue
//===>src/views/Film/Comingsoon.vue
<template>
<div>
<ul>
<li v-for="data in $store.state.comingList" :key="data.filmId">
<img :src="data.poster" />
<h3>{{data.name}}</h3>
<p>观众评分{{data.grade}}</p>
<p>主演:{{data.actors |actorfilter}}</p>
</li>
</ul>
</div>
</template>
<script>
export default {
mounted() {
if (this.$store.state.comingList.length === 0) {
this.$store.dispatch("getComingListAction");
} else {
console.log("使用缓存数据");
}
}
};
</script>
<style lang="scss" scoped>
ul {
li {
padding: 10px;
overflow: hidden;
img {
float: left;
width: 100px;
}
}
}
</style>
2.修改store文件
//===>src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
//自定义的共享状态
isTabbarShow: true,
comingList: []
},
mutations: {
HideMaizuoTabbar(state, data) {
state.isTabbarShow = data
},
commingListMutation(state, data) {
state.comingList = data;
}
},
actions: {
// 异步处理
getComingListAction(store) {
axios({
url: 'https://m.maizuo.com/gateway?cityId=120100&pageNum=1&pageSize=10&type=2&k=8283002',
headers: {
'X-Client-Info': '{"a":"3000","ch":"1002","v":"5.0.4","e":"159065562332628866547713"}',
'X-Host': 'mall.film-ticket.film.list'
}
}).then(res => {
console.log(res.data);
store.commit('commingListMutation', res.data.data.films)
})
}
},
modules: {
}
})
第二次点击的确使用缓存加载的
我们点击进入Comingsoon组件,在mounted()生命周期函数中,判断store中的comingList有没有数据。有数据就直接用,没有数据的话,我们通过this.$store.dispatch("getComingListAction");来分发名字为getComingListAction的action。这个时候,会执行第二步中actions的定义的同名方法,异步调接口获取数据。获取到数据之后,我们再用mutations来更新数据。这个时候,第一步的$store.state.comingList就改变了。
mapState
mapState可以很方便的获取store中state里面的属性值,配合computed()计算属性使用,具体用法是:
1.修改App.vue
//===>src/App.vue
<template>
<div>
<tabbar v-show="isTabbarShow" />
...
</div>
</template>
<script>
...
import { mapState } from "vuex";
export default {
...
computed: {
...mapState(["isTabbarShow"])
}
};
</script>
<style lang="scss">
...
</style>
此时,效果会和之前的一样。
getters
我们要实现,从接口获取到了很多条数据,但只想显示三条。这个功能使用store该怎么做呢?
1.在store文件中添加getters方法
//===>src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
//自定义的共享状态
isTabbarShow: true,
comingList: []
},
getters: {
comingListGetter(state) {
return state.comingList.filter((item, index) => index < 3)
}
},
mutations: {
HideMaizuoTabbar(state, data) {
state.isTabbarShow = data
},
commingListMutation(state, data) {
state.comingList = data;
}
},
actions: {
// 异步处理
getComingListAction(store) {
axios({
url: 'https://m.maizuo.com/gateway?cityId=120100&pageNum=1&pageSize=10&type=2&k=8283002',
headers: {
'X-Client-Info': '{"a":"3000","ch":"1002","v":"5.0.4","e":"159065562332628866547713"}',
'X-Host': 'mall.film-ticket.film.list'
}
}).then(res => {
console.log(res.data);
store.commit('commingListMutation', res.data.data.films)
})
}
},
modules: {
}
})
2.在需要接受数据的地方,使用store中提供的getters方法
<template>
<div>
<ul>
<li v-for="data in $store.getters.comingListGetter" :key="data.filmId">
...
</li>
</ul>
</div>
</template>
<script>
...
</script>
<style lang="scss" scoped>
...
</style>
效果就不展示了,因为疫情期间电影数据列表的内容不足三条。
mutation常量风格
1.新建mutation常量
//===>src/type/index.js
export const HIDE_TABBAR_MUTATION = 'hide'
export const SHOW_TABBAR_MUTATION = 'show'
2.在store中引入常量
//===>src/store/index.js
...
import { HIDE_TABBAR_MUTATION, SHOW_TABBAR_MUTATION } from '@/type'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
...
},
getters: {
...
},
mutations: {
// HideMaizuoTabbar(state, data) {
// state.isTabbarShow = data
// },
[HIDE_TABBAR_MUTATION](state, data) {
state.isTabbarShow = data
},
commingListMutation(state, data) {
state.comingList = data;
}
},
actions: {
...
},
modules: {
}
})
3.修改Detail页面,时期使用常量风格的mutation
//===>src/views/Film/Detail.vue
<template>
...
</template>
<script>
...
import { HIDE_TABBAR_MUTATION, SHOW_TABBAR_MUTATION } from '@/type'
export default {
...
beforeMount() {
// bus.$emit("maizuo", false);
this.$store.commit(HIDE_TABBAR_MUTATION, false);
},
...
beforeDestroy() {
// bus.$emit("maizuo", true);
this.$store.commit(HIDE_TABBAR_MUTATION, true);
},
...
};
</script>
<style lang="scss" scoped>
...
</style>
VueX总结
(1)应用层级的状态应该集中到单个store对象中。
(2)提交mutation是更改状态的唯一方法,并且这个过程是同步的。
(3)异步逻辑都应该封装到action里面。
网友评论