参考:
详解vuex 解决多个组件之间的通信问题_Allen的博客-CSDN博客
详解vuex
1.安装 yarn add vuex2.引入vuex 并且让vue使用vuex新建文件src/store/index.js(仓库)
//引入vueximport Vuex from "vuex"import Vue from "vue"Vue.use(Vuex) //让vue使用Vuex//创建store仓库let store = new Vuex.Store({//里面写store相关的配置项})export default store; //需要暴露出去12345678
3.在main.js入口文件里注册store//引入vuex的实例import store from "./store"new Vue({ render: h => h(App), router, //就是为了让每一个组件都可以访问到路由相关的api ($router/$route) store //目的就是为了让每一个组件都可以访问到vuex相关的api ($store)}).$mount('#app')12345674.在仓库中index.js 定义 以及更改状态定义isTababrShow 以及 更改isTabbarShow状态的方法
//创建storelet store = new Vuex.Store({ state:{ //就是用来定义多组件之间的共享状态 isTabbarShow:true }, mutations:{ //如vuex流程图,只要mutations有权限更改state, //同时这里也提供了很多更改状态的方法 show(state){ state.isTabbarShow = true }, hide(state){ state.isTabbarShow = false } } })1234567891011121314155.在主入口文件App.vue里面对状态进行关联 <Tabbar v-show="$store.state.isTabbarShow"></Tabbar> 16.在Search.vue触发钩子函数一进入search页面不让tabbar显示
created(){ //一进入search,需要更改仓库isTabbarShow将其变成false this.$store.commit("hide") }, beforeDestroy(){ //一旦离开search,isTabbarShow true this.$store.commit("show") }12345678
同步操作闭环形成
通过vuex异步请求数据
Cinema.vue
toSearch(){this.$router.push("/search")}123发现Search与Cinema组件中的数据都是一致的,不需要进入到每个组件都请求一次数据,可以在vuex中的action里面进行异步请求即可。
1.在仓库中定义以及更改状态store/index.js
state:{ //就是用来定义多组件之间的共享状态 this.$store.state.isTabbarShow isTabbarShow:true, cinemaList:[]},
actions:{ getCinemaListAction(context){ instance.get("/gateway?cityId=310100&ticketFlag=1&k=2654330",{ headers:{ 'X-Host': 'mall.film-ticket.cinema.list' } }).then(res=>{ // 如何更改vuex中的cinemaList这个状态? // 需要触发mutations的setCinemaList这个方法 // 第一个参数就是触发的具体的mutations的名称 第二个参数就是给其传入的异步请求获取到的数据 context.commit("setCinemaList",res.data.data.cinemas) }) } }, mutations:{ //后续唯一可以更改state的地方 show(state){ //组件中如何调用此方法? this.$store.commit("方法名") state.isTabbarShow = true }, hide(state){ state.isTabbarShow = false }, setCinemaList(state,cinemaList){ //第二个参数可以接受外面传递过来的参数 state.cinemaList = cinemaList } }})12345678910111213141516171819202122232425262728293031322.在Cinema组件中进行触发action的方法:created(){ //需要调用dispatch触发vuex的action方法 this.$store.dispatch("getCinemaListAction") }1234需要在Cinema中使用vuex的状态cinemaList
cinemaArea(){ let newArr = this.$store.state.cinemaList.map(item=>{ return item.districtName }) return ["全城",...new Set(newArr)]},filterCinemaArea(){ if(this.currentArea === "全城") return this.$store.state.cinemaList; return this.$store.state.cinemaList.filter(item=>{ return item.districtName === this.currentArea ? true : false })}123456789101112回到Search页面,发现vuex的全局状态管理的优势体现出来了。多组件数据共享
3.vuex存储是内存,一刷新就没有了,如果不刷新界面,可以实现多组件的数据共享。因为vuex中的数据存内存中的,一刷新就会恢复初始值。Search.vue
created(){ if(this.$store.state.cinemaList.length>0){ console.log("vuex中的cinemaList数据有了...") }else{ //刷新了 vuex中没有数据 this.$store.dispatch("getCinemaListAction") } this.$store.commit("hide") },12345678vuex的getters获取5条影院数据开始是在Search.vue里
getCinemaListFive(){ //组件的computed依赖于data数据return this.$store.state.cinemaList.slice(0,5)},123如果在别的地方,也需要用到vuex的5条数据的话,也得需要写一次上述的计算属性。
需要在store/index.js里面的getters去进行单独的定义了。
getters:{ //类似于computed计算属性 只不过里面的数据依赖于vuex的状态 getCinemaListFive(state){ return state.cinemaList.slice(0,5) }, },12345之后在Search.vue里去调用
<li v-for="data in $store.getters.getCinemaListFive" :key="data.cinemaId">{{data.name}}</li>1234vuex辅助函数(mapState,mapGetters,mapActions,mapMutations)
mapStatemapState这个辅助函数就是为了方便获取vuex中的状态,本来获取状态 this.$store.state.xxx
import { mapState } from 'vuex'
computed:{ ...mapState(["cinemaList"]), cinemaArea(){ //获取vuex的状态,直接通过this既可以访问到了 let newArr = this.cinemaList.map(item=>{ return item.districtName }) return ["全城",...new Set(newArr)]},filterCinemaArea(){ if(this.currentArea === "全城") return this.cinemaList return this.cinemaList.filter(item=>{ return item.districtName === this.currentArea ? true : false })}}12345678910111213141516171819后续如果你的computed中有跟vuex的同名的,需要通过这种方式设置
...mapState({ aaa:state=>state.cinemaList }),123mapGetters这个辅助函数与mapState的用法一模一样
import {mapState,mapGetters} from "vuex"1computed:{ ...mapState(["cinemaList"]), ...mapGetters(["getCinemaListFive"]),}1234 v-for="data in getCinemaListFive" //$store.getters.getCinemaListFive1modules因为store是单一的数据源,项目中创建的store的实例只能是一个,所以数据全都放在这一个大的实例对象中,很难去维护,所以需要对于store进行模块划分。
store/module/tabbar.js
const tabbar = { namespaced: true, state:{ isTabbarShow:true, }, mutations:{ show(state){ //组件中如何调用此方法? this.$store.commit("方法名") state.isTabbarShow = true }, hide(state){ state.isTabbarShow = false } }}
export default tabbar;12345678910111213141516store/module/cinema.js
import {instance} from "@/utils/http"const cinema = { namespaced: true, state:{ cinemaList:[] }, getters:{ getCinemaListFive(state){ return state.cinemaList.slice(0,5) }, }, actions:{ getCinemaListAction(context){ instance.get("/gateway?cityId=310100&ticketFlag=1&k=2654330",{ headers:{ 'X-Host': 'mall.film-ticket.cinema.list' } }).then(res=>{ // 需要触发mutations的setCinemaList这个方法 // 第一个参数就是触发的具体的mutations的名称 第二个参数就是给其传入的异步请求获取到的数据 context.commit("setCinemaList",res.data.data.cinemas) }) } }, mutations:{ setCinemaList(state,cinemaList){ state.cinemaList = cinemaList } }}
export default cinema;1234567891011121314151617181920212223242526272829303132store/index.js
import tabbar from "./module/tabbar"import cinema from "./module/cinema"
//创建storelet store = new Vuex.Store({ modules: { //通过modules将所有的分支的模块进行合并 tabbar, cinema }})
1234567891011Cinema.vue
...mapState("cinema",["cinemaList"]), //前提一定需要在module模块里面声明namespace:true1派发方法,也得需要按照指定的模块名字请求action与mutations
this.$store.dispatch("cinema/getCinemaListAction")1Search.vue
...mapState("cinema",["cinemaList"]),...mapGetters("cinema",["getCinemaListFive"]),12created(){ if(this.cinemaList.length>0){ }else{ //dispatch("module名字/action方法") this.$store.dispatch("cinema/getCinemaListAction") } //commit("module名字/commit方法") this.$store.commit("tabbar/hide") }, beforeDestroy(){ //commit("module名字/commit方法") this.$store.commit("tabbar/show") }1234567891011121314App.vue
import {mapState} from "vuex"
computed:mapState("tabbar",["isTabbarShow"])123<Tabbar v-show="isTabbarShow"></Tabbar> 1Search
<button @click="back">取消</button>methods:{ back(){ this.$router.back() }},123456mapActions这个辅助函数用法与上面一致,但是需要定义在methods里面
import { mapState,mapActions } from 'vuex'1methods:{ ...mapActions("cinema",["getCinemaListAction"]),}123created(){ if(this.cinemaList.length === 0){ // this.$store.dispatch("cinema/getCinemaListAction") this.getCinemaListAction() } }123456mapMutations这个辅助函数用法与上面一致的用法
import {mapState,mapGetters,mapMutations,mapActions} from "vuex"1methods:{ ...mapActions("cinema",["getCinemaListAction"]), ...mapMutations("tabbar",["show","hide"]),}1234created(){ if(this.cinemaList.length>0){
}else{ //刷新了 vuex中没有数据 this.getCinemaListAction() } this.hide()},beforeDestroy(){ this.show()}
123456789101112vuex 项目结构Vuex 并不限制你的代码结构。但是,它规定了一些需要遵守的规则:
应用层级的状态应该集中到单个 store 对象中。提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。异步逻辑都应该封装到 action 里面。只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 action、mutation 和 getter 分割到单独的文件。————————————————版权声明:本文为CSDN博主「Allen 赵奇隆」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/zqlbanzhuan/article/details/109045145