Vuex实战

75 阅读4分钟

Vuex实战

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
英译:

dispatch 派遣;调遣;派出;发出,发送
state 状态
actions 行动 所做之事
mutations 变异,突变
commit 承诺,保证(做某事、遵守协议或遵从安排等)
payload 有效载荷 装载量

1.0 安装

初始化一个基于webpack的vue项目

vue init webpack vue2-vuex

打开文件夹安装vuex

npm install vuex@3.1.0 --save

注意版本,我用的是 npm install vuex@3.1.0 --save

2.0 创建文件

在src文件夹下创建 store文件,然后创建index.js 里面内容如下

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);

const store = new Vuex.Store({
  state:{ // 定义全局状态
    count:1
  },
});
export default store 

再然后在 main.js里面引入

import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
    el: '#app',
    // 注册到vue里面,让vue项目拥有vuex的功能
    // 给vue实例原型链上的$store属性赋值 
    store,
    router,
    components: { App },
    template: '<App/>'
})

3.0 state里面值的使用

1.0 直接使用 this.$store.state.变量名(取值)
2.0 用辅助函数 mapState 获取

<div class="hello">
    <h2>直接使用1:{{$store.state.count}}</h2>
    <h2>直接使用2:{{num}}</h2>
    <h2>辅助函数使用:{{count}}</h2>
    <h2>别名:{{number}}</h2>
</div>
import {mapState} from 'vuex'
export default {
    name: 'HelloWorld',
    data () {
        return {
            msg: 'Welcome to Your Vue.js App',
            num:''
        }
    },
    computed:{
        ...mapState(['count']),
        // 也可以起别名
        ...mapState({number:'count'})
    },
    created() {
        this.num = this.$store.state.count // 因为只赋值了一次,以后count改变 num不会变
    },
}

4.0 定义mutations同步数据

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。

语法:

const store = new Vuex.Store({
  state:{
    count:1
  },
  mutations:{ // 修改变量值
    addCount(state,value){ // 增加数据
      state.count += value
    },
    subCount(state,value){ // 减少数据
      state.count -= value
    },
  }
});

使用mutations的2中方法:

1.0 直接使用 this.$store.commit('mutations里面的函数名')
2.0 映射使用 mapMutatios

// 增加两个按钮
<button  @click="add()">增加数据</button>
<button @click="sub()">减少数据</button>
// 方法里面增加两个方法
methods:{
    add(){
        this.$store.commit('addCount',10)
    },
    sub(){
        this.$store.commit('subCount',8)
    }
},
// 然后点击就会 发生改变

使用mapMutations

// 先引入
import {mapState,mapMutations} from 'vuex'
methods:{
...mapMutations(['addCount','subCount']),
     add(){
      this.addCount(10)
      //this.$store.commit('addCount',10)
    },
    sub(){
        this.subCount(10)
        //this.$store.commit('subCount',8)
    }
}

Tips:

// 参数这边官方建议传递一个对象,而不是一个值,这样更美观,其实我觉的是后面人看代码更好理解
mutations:{
    addCount(state,payload){
      state.count += payload.number
    }
}
// 页面方法
add(){
    this.$store.commit('increment',{number:666}) //每次都加666
}

5.0 了解异步操作 Actions

在 mutation 中混合异步调用会导致你的程序很难调试。例如,当你调用了两个包含异步回调的 mutation 来改变状态,你怎么知道什么时候回调和哪个先回调呢?这就是为什么我们要区分这两个概念。在 Vuex 中,mutation 都是同步事务:
修改store/index.js

const store = new Vuex.Store({
  state:{
    count:1,
    name:'小红'
  },
  mutations:{
      addCount(state,value){ // 增加数据
          state.count += value
      },
  },
  actions:{ // 异步操作在这里
      asyncAddCount(content,num){ // content 默认参数 与 store 实例具有相同方法和属性
        return new Promise((resolve,reject)=>{
          setTimeout(()=>{
            content.commit('addCount',num)
            resolve()
          },2000)
        })
      }
  },
});

actions:调用的两种方法

1.0 直接使用 this.$store.dispatch('actions里面的函数名')
2.0 映射使用 mapActions

// 1.0 修改点击事件
add(){
    //this.addCount(10)
    //this.$store.commit('addCount',10)
    this.$store.dispatch('asyncAddCount',88)
},

映射法:

// 引入辅助函数
import {mapState,mapMutations,mapActions} from 'vuex'
// 使用
methods:{
...mapMutations(['addCount','subCount']),
...mapActions(['asyncAddCount']),
        add(){
        //this.addCount(10)
        //this.$store.commit('addCount',10)
        //this.$store.dispatch('asyncAddCount',88)
        this.asyncAddCount(88)
    },
},

看了例子,是不是明白了,actions就是去提交mutations的,什么异步操作都在actions中消化了,最后再去提交mutations的。

6.0 Getter修饰器

比如我们上面的count,需要我们在前面全部加一个字符串“hello”,当然我们在页面就可以直接加,但是如果页面很多,我们就要修改很多次, 如果要把“hello”,变成“fuck”了,我们又要去多个页面修改。所有就出现了Getter这个修饰器。
语法:

// store.js
const store = new Vuex.Store({
  state:{
    count:1,
  },
  getters:{
    getCount(state){
      return 'hello '+state.count
    },
  }
});
<h2>getters方法1:{{gCount}}</h2>
<h2>getters方法2:{{getCount}}</h2>
<h2>getters方法(别名):{{qqww}}</h2>

import {mapState,mapMutations,mapActions,mapGetters} from 'vuex'

computed:{
...mapGetters(['getCount']), // 注意用的时候名字 就叫 ‘getCount’
    //别名
...mapGetters({qqww:'getCount'}) 
},
created() {
    this.gCount = this.$store.getters.getCount // hello1
    // 注意 如果 count的数值修改 gCount不会修改,因为赋值操作只执行了一次,而在computed计算属性里里面的会随之变化
},

7.0 项目结构

我们目前就这一个index.js 假设如果我们这个页面内容很多很多,那以后看起来或者维护起来就麻烦了,所以我们把这个页面拆分一下 1.8415b8e8.jpg index.js里面大致包含state/getters/mutations/actions这四个属性,我们可以彻底点,index.js里面就保持这个架子,把里面的内容四散到其他文件中。
state.js

export const state = {
  count:1,
  name:'小红'
}

getters.js

export const getters = {
    getCount(state){
    return 'hello '+state.count
  },
}

mutations.js

export const mutations = {
  increment(state,payload){
    state.count += payload.number
  }
}

actions.js

export const actions =  {
  setNum(content,payLoad){
    return new Promise((resolve,reject)=>{
      setTimeout(()=>{
        content.commit('increment',{number:payLoad.number})
        resolve()
      },1000)
    })
  }
}

最后我们的index.js

import Vue from 'vue'
import Vuex from 'vuex'
import {state} from './state'
import {getters} from "./getters";
import {mutations} from "./mutations";
import {actions} from "./actions";

Vue.use(Vuex);

const store = new Vuex.Store({
  state:state,
  getters:getters,
  mutations:mutations,
  actions:actions
});
export default store

以上就是简单的进行了按属性进行拆分store里面的代码,这样就比较清晰了哈,你需要加什么就去哪里加,大家各干各的,互不影响。
当然,你完全可以不这么做,引用官方文档中的一句话,“需要多人协作的大型项目中,这会很有帮助。但如果你不喜欢,你完全可以不这样做”。

8.0 vuex-modules定义-分模块

我们上面已经把vuex按功能分开了,但是还是不行,比如很大的项目,我想按功能划分就有点捉襟见肘了
所有我们就有了分模块

// 新建两个模块
// user.js 用户模块
// 注意state 变成了函数
export const userModel = {
    namespaced:true, // 加上命名空间之后就不怕 方法重复了
    state(){
        return{
            name:'小红',
            age:18
        }
    },
    getters:{

    },
    mutations:{
        setName(state,value){
            state.name = value
        },
    },
    actions:{

    },
}


// cart.js 购物车模块
export const cardModel = {
    namespaced:true, // 加上命名空间之后就不怕 方法重复了
    state(){
        return{
            list:[{size:'185',age:18,color:'red'}]
        }
    },
    getters:{

    },
    mutations:{

    },
    actions:{

    },
}

// 修改 index.js
import Vue from 'vue'
import Vuex from 'vuex'
import {userModel} from "./mudules/user";
import {cardModel} from "./mudules/cart";

Vue.use(Vuex)

const store = new Vuex.Store({
    modules:{ // 小模块注册
        userModel,
        cardModel,
        // 取别名
        // uuser:userModel
    }
});
export default store

如何取值

注意: 分模块后影响state里面的取值,其它的方法暂时不变

1.0 直接取值 this.$store.state.模块名.变量名

// 分模块后写法
...mapState({
    '变量名':state => state.模块名.变量名
})
<h2>{{name}}</h2>
<h2>{{list}}</h2>
// 取值先
computed:{
...mapState({
        name: (state) => {
            return state.userModel.name
        },
        list: (state) => {
            return state.cartModel.list
        },
    }),
// 其它写法
...mapState('userModel',['name']),
...mapState('userModel',{nnn:'age'})
}

分模块后 mutatios的用法

// 1.0
this.$store.commit('userModel/setName','大大的大')
// 2.0 映射使用

methods:{
...mapMutations('userModel',['setName']),
    add(){
      this.setName('小小小')
    },
},
// 或者
methods:{
...mapMutations('userModel',{ooName:'setName'}),
   add(){
    this.ooName('小小小')
    },
}
// 与之相关的Actions 和 getters的用法是一样的

总结

以上就是vuex的基本操作了,希望大家学以致用。

你要克服懒惰,你要克服游手好闲,你要克服漫长的白日梦,你要克服一蹴而就的妄想,你要克服自以为是浅薄的幽默感。你要独立生长在这世上,不寻找不依靠,因为冷漠寡情的人孤独一生。你要坚强,振作,自立,不能软弱,逃避,害怕。不要沉溺在消极负面得情绪里,要正面阳光得对待生活和爱你的人。

扫码_搜索联合传播样式-白色版.png