前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >组件通信解决办法之vuex

组件通信解决办法之vuex

作者头像
切图仔
发布2022-09-08 15:52:12
4300
发布2022-09-08 15:52:12
举报
文章被收录于专栏:生如夏花绚烂生如夏花绚烂

vuex实现组件全局通信,不用像以前那样子组件要不断找父组件,找爷爷,找祖先..... 通过vuex可实现数据跨组件共享,防止数据意外修改,调试方便 摘自官方的图片

State:数据 Mutations:操作 Actions:调用 Actions->Mutaions->State 我们不能直接对state进行操作,必须定义对应的Mutaions才能对State进行操作 而Devtools则是监控Mutations,比如谁调用了Multaion传递了什么参数等 但是组件又不能直接调用Mutations,这里就要通过Actions去调用Mutaions。 当State发生改变时,会通过组件调用Actions,Actions在调用Mutations,通过Mutations修改State。

需要注意的是Mutations是同步操作,Actions可以是异步操作,也就是当要进行ajax、读写文件等异步操作时应该在Actions执行,当异步操作完毕后在将结果同步的方式给Mutations

简单使用Vuex

1.下载引入

代码语言:javascript
复制
cnpm i vuex -D
//vuex
import Vuex from 'vuex';

2.添加到vue对象

代码语言:javascript
复制
//添加到vue
Vue.use(Vuex);

3.声明store对象

代码语言:javascript
复制
//声明store对象
const store = new Vuex.Store({
  // strict:true,//严格模式,防止直接修改state(开发阶段)
  strict:process.env.NODE_ENV!='production',
  state:{a:12,b:4,c:45},
  mutations:{},//mutaion
  actions:{},//调用mutaions
  getters:{},
  modules:{}//模块
})

4.挂载到vm对象

代码语言:javascript
复制
new Vue({
  el: '#app',
  router,
  store,//挂到vm
  components: { App },
  template: '<App/>'
})

接下来在任意地方访问 {{$store.state}} 输出如下

代码语言:javascript
复制
{ "a": 12, "b": 4, "c": 45 }

当我们尝试对state直接修改时

代码语言:javascript
复制
fn(){
         this.$store.state.a+=4
     }

抛出如下异常

代码语言:javascript
复制
Error: [vuex] do not mutate vuex store state outside mutation handlers."

我们修改数据应该是 Actions->Mutations->State 我们在store对象添加mutaions和actions

代码语言:javascript
复制
//声明store对象
const store = new Vuex.Store({
  // strict:true,//严格模式,防止直接修改state(开发阶段)
  strict:process.env.NODE_ENV!='production',
  state:{a:12,b:4,c:45},
  mutations:{
    add(state,n){
      state.a+=n
    }
  },//mutaion
  actions:{
    add(context,n){
      // context当前store对象
      context.commit('add',n)//调用mutaions
    }
  }
  getters:{},
  modules:{}//模块
})

调用

代码语言:javascript
复制
   this.$store.commit('add',5)//直接调用mutaions
     //调用actions->muataions
   this.$store.dispatch('add',5)//一个action可以有多个mutation

在涉及到state里面的数据计算时我们可以使用getters,相当于computed

代码语言:javascript
复制
...
actions:{
    add(context,n){
      // context当前store对象
      context.commit('add',n)
    }
  },//调用mutaions
  getters:{
      count(state){
        return state.a+state.b
      }
  },//类似于computed
  modules:{}//模块

当访问时,我们需要{{$store.getters.count}}才能获取到count,但是这样太麻烦了,还不如直接用state 因此我们可以利用计算属性

代码语言:javascript
复制
computed:{
    //可读可写
    count(){
       return this.$store.getters.count
    }
  }

这样我们就可以直接使用count了,到这好像要搞复杂了,多搞了层computed,但是这样这样做有好处,computed可以读取和设置,设置时我们可以直接调用actions进行操作,而不用绑定method在调用actions

代码语言:javascript
复制
  count:{
      get(){
        return this.$store.getters.count
      },
      set(value){
         this.$store.dispatch.....
      }
      
    }

但是这样也有点麻烦,如果getters很多,我们就要不断进行get,set,而且每个页面都要如此

如何解决这个问题? 通过vuex里面的辅助方法

vuex辅助方法

mapState:将State映射成computed mapActions:将Actions映射成methods mapGetters:将Getters映射computed

这样问题不就简单了吗,我们直接调用方法即可触发actions,并且直接放在state的值 示例如下

代码语言:javascript
复制
import {mapState,mapActions,mapGetters} from 'vuex';
  methods:{
    del(id){
      this.datas = this.datas.filter(data=>data.id!=id)
    },
    ...mapActions(['setA','setB'])
  },
  computed:{
      ...mapState(['a','b','c','count']),
      ...mapGetters(['count'])
    
  }

在store里面我们对state,mutations,actions进行了定义

代码语言:javascript
复制
new Vuex.Store({
  // strict:true,//严格模式,防止直接修改state(开发阶段)
  strict:process.env.NODE_ENV!='production',
  state:{a:12,b:4,c:45},
  mutations:{
    setA(state,n){
      state.a+=n
    },
    setB(state,n){
        state.b+=n
    }
  },//mutaion
  actions:{
    setA({commit},n){
        commit('setA',n)
    },
    setB({commit},n){
        commit('setB',n)
    }
  },//调用mutaions
  getters:{
      count(state){
        //不能修改
        return state.a+state.b
      }
  },//类似于computed
  modules:{}//模块

我们直接调用对应属性,方法即可

代码语言:javascript
复制
<div class="hello">
    a:{{a}}
    b:{{b}}
    count:{{count}}
        <input type="button" value="a+5" @click='setA(5)'>
    <input type="button" value="b+5" @click='setB(5)'>
</div>
vuex配合服务器
代码语言:javascript
复制
mutations:{
    setUsers(state,users){
      state.users = users
    }
  },
  actions:{
    async readUsers({commit}){
     let res = await fetch('http://127.0.0.1:3000/users.txt');
     let users = await res.json();
     commit('setUsers',users)
    }
  }
    //调用actions
    ...
    index.vue
  created(){
    this.readUsers();
  },
  methods:{
    del(id){
      this.datas = this.datas.filter(data=>data.id!=id)
    },
    ...mapActions(['setA','setB','readUsers'])
  },
    ....
模块

modules帮我们拆分store有时候store较大时我们需要将store拆分成多个子store 如下例

代码语言:javascript
复制
import Vue from 'vue';
import Vuex, { Store } from 'vuex';
//添加到vue
Vue.use(Vuex);
//子store
let store_a = {
  state:{
    str:'store_a'
  }
}
let store_b = {
  state:{
    str:'store_b'
  }
}
//声明store对象
let store = new Vuex.Store({
  // strict:true,//严格模式,防止直接修改state(开发阶段)
  strict:process.env.NODE_ENV!='production',
  state:{a:12,b:4,c:45,users:null},
  mutations:{
    setA(state,n){
      state.a+=n
    },
    setB(state,n){
        state.b+=n
    },
    setUsers(state,users){
      state.users = users
    }
  },//mutaion
  actions:{
    setA({commit},n){
        commit('setA',n)
    },
    setB({commit},n){
        commit('setB',n)
    },
    async readUsers({commit}){
     let res = await fetch('http://127.0.0.1:3000/users.txt');
     let users = await res.json();
     commit('setUsers',users)
    }
  },//调用mutaions
  getters:{
      count(state){
        //不能修改
        return state.a+state.b
      },
      async onlineUsers(state,getters,context){
        //当数据发生变化时执行
        if(!state.users){
         await store.dispatch('readUsers');
        }
        //getters写出异步不能直接配合computed computed不能异步
        
        return state.users.filter(user=>user.online)
      }
  },//类似于computed
  modules:{
    store_a,
    store_b

  }//模块
})
export default store;

我们添加了两个子模块,这两个子模块也可以有父store的成员如state,mutaions等、 当访问子模块时

代码语言:javascript
复制
  a_str:{{$store.state.store_a.str}}<br />
  b_str:{{$store.state.store_b.str}}

有点麻烦,我们可以通过computed解决

代码语言:javascript
复制
...
 computed:{
      ...mapState(['a','b','c','count','users']),
      ...mapState({
        str_a:state=>state.store_a.str,
        str_b:state=>state.store_b.str,
      }),
      ...mapGetters(['count'])
  }
...

直接输出

代码语言:javascript
复制
{{str_a}}
{{str_b}}

actions和mutation没有自己独立的空间

也就是子store的actions/mutaions名字重复时会被同时触发

我们也可以在子模块添加namespaced:true时action和mutations有自己的作用域

模块命名空间

需要注意的是加了这个属性后我们要使用命名空间来调用

代码语言:javascript
复制
...mapActions(['a/update'])//调用a模块的update
动态加载模块

有时候业务逻辑需要我们可能要按需加载某个模块,这个时候可以使用vuex提供的动态加载模块功能

代码语言:javascript
复制
//index.js
store.registerModule('c',{
    state:{
            text::3
        }
})
//解绑
store.unregisterModule('c')
其他API

监听 第一个参数为一个方法,返回要监听的值 第二个参数为要监听的值发生变化时执行的逻辑

代码语言:javascript
复制
store.watch((state)=>state.count,(newCount)=>{
    console.log('new count watched'.newCount)
})

订阅 拿到所有mutations的变化,每次调用mutation执行相关逻辑

代码语言:javascript
复制
store.subscribe((mutation,state)=>{
   console.log(mutation.type)//调用了哪个mutation
   console.log(mutation.payload)//mutation接收的参数
})

监听action

代码语言:javascript
复制
store.subscribeAction((action,state)=>{
    console.log(action.type)//调用了哪个action
    console.log(action.payload)//接收的参数
})
插件
代码语言:javascript
复制
...
const store = new Vuex.Store({
        state:defalutState,
        mutations,
        getters,
        plugins:[
            //每一个方法都是一个插件接收store对象
            (store)=>{
               

            }
        ]
    })
...
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-07-25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简单使用Vuex
  • vuex辅助方法
  • vuex配合服务器
  • 模块
  • 模块命名空间
  • 动态加载模块
  • 其他API
  • 插件
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档