vue入门之vuex五大属性及动态配置(6)

1,959 阅读4分钟

个别杠精会说vuex是历史的产物,在下实在不敢苟同。不予回复。

建议初学者一步一脚印,切莫装B,毕竟我们都是站在巨人肩膀上的一员

一、Vuex的五大属性

**简述:为了让初学者有个概念上的认知,以下介绍仅使用大白话进行阐述,**详情请查阅官网vuex.vuejs.org/zh/guide/

vuex 中最关键的是store对象,这是vuex的核心。可以说,vuex这个插件其实就是一个store对象,每个vue应用仅有一个store对象。

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

Vuex.Store可以理解为一个全局的存储对象,该对象中有五个重要的属性如下所示,它们各司其职,又可以可以互相配合利用。下面我就介绍下它们各自的作用。

1.State :

存放数据的数据源

定义:

const store = new Vuex.Store({
  state: {
    List:[1,2,3,4,5,6,7]
  }
})

组件中使用:

<script>
  export default {
    computed: {
      list() {
        return this.$store.state.List.filter(item => item > 3);      }
    }
 }
</script>

结果:

获取数据源中的List数组,并进行过滤,输出的结果为 [4,5,6,7]。

如果其它组件也需要这种过滤的数据怎么操作呢?也许你会copy这行代码,放到需要的组件中去。那么问题又来了,甲方爸爸变更需求将>3变更成>6怎么办?你是不是需要到各个组件中去依次修改,这么无疑加大了工作量。怎么解决这种问题呢,请继续往下看。

2.Getter :

从 store 中的 state 中派生出一些状态,例如对state中List进行过滤

定义:

const store = new Vuex.Store({
  state: {
    List:[1,2,3,4,5,6,7]
  },
  getters: {
    getListMax: state => {
      return state.List.filter(item => item > 3)    
    }
  }
})

组件中使用:

<script>
  export default {
    computed: {
      list() {
        return this.$store.getters.getListMax
        }
    }
  }
</script>

这样**(1)中到问题就解决了,如果需求变更只需要在getters中到getListMax做修改即可**

3.注:Getter依赖

getter 可以依赖其它已经定义好的 getter

定义:

const store = new Vuex.Store({
  state: {
    list: [1, 2, 3, 4, 5, 6, 7]
  },
  getters: {
    getListMax: state => {
      return state.List.filter(item => item > 3)
    },
    listCount: (state, getters) => {
      return getters.getListMax.length;
    }
  }
})

组件中使用:

<script>
  export default {
    computed: {
      list() {
        return this.$store.getters.getListMax
      },
      listCount() {
        return this.$store.getters.listCount
     }    }
  }
</script>

输出的结果为:列表[4,5,6,7]    长度4

4.Mutation: 

用来更改state中数据源的唯一方法;

Mutation 必须是同步函数:

加深理解可参考:
1.www.jianshu.com/p/d071e205b…
2.www.zhihu.com/question/48…

当然你非要写成异步也没人拦着你,但是国有国法,家有家规,在编程学习的道路上,还是要遵循正规军的步伐。

定义:

很多小伙伴会对官网中的 每个 mutation 都有一个字符串的事件类型 (type) 和 一个 回调函数 (handler)这句话表示不理解”,请结合下方代码的注释进行理解。

const store = new Vuex.Store({
  state: {
    List: [1, 2, 3, 4, 5, 6, 7]
  },
  mutation:{
    //事件类型 (type) :“changeList”
    changeList(state,payload) {        //回调函数(handler):就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数      state.List[0]=99+payload.num       }
  }
})

组件中使用:

向 store.commit 传入额外的参数,即 mutation 的 载荷(payload):大多数情况下载荷是一个对象

<script>
  export default {
     created:{
        this.startMu()
        console.log(this.$store.state.List[0])
     },
     methods: {
        startMu(){
            this.$store.commit('changeList',{
                num:1
            })
        }
     }
  }
</script>

调用的方式也可以写成

this.$store.commit({
    type:'changeList',//type属性指向的即为mutation的方法名
    num:1
})

输出结果:  100;

5.Action :

Action 提交的是 mutation,通过mutation改变state中的数据。

Action 可以包含任意异步操作

定义:

const store = new Vuex.Store({
  state: {
    List: [1, 2, 3, 4, 5, 6, 7]
  },
  mutation:{
      changeList(state,payload) {  
      state.List[0]=99+payload.num   
    }
  },
  actions: {
      changeListAsync (context) {
        return new Promise((resolve, reject) => {
            context.commit('changeList',{num:1})
         }).catch(error => {
            reject(error)
      })
    }
 }})

组件中使用:

<script>
  export default {
     created:{
        this.startAc()     },
     methods: {
      startAc(){
        this.$store.dispatch('changeListAsync')
        }
     }
  }
</script>

结果跟(4)中的一样,

在实际场景的应用中仅靠mutations的同步操作是不满足实际需求的,vuex的acitons,就解决了这个问题,可以执行异步操作,是用来解决mutations只有同步无异步的问题

6.扩展运算符(...)结合辅助函数实现vuex属性映射

(1.)辅助函数:mapState、mapGetters、mapActions、mapMutations
**(2).**mapState为例,其余可自行百度,目的都是一样,减少代码的重复性,提高编写效率:

定义:

const store = new Vuex.Store({
  state: {
    a:1,
    b:2,
    c:3
  }
})

组件中使用:

<template>
  <div>{{this.a}}</div> 
  <div>{{this.b}}</div>
</template>
<script>
  export default {
    computed: {
        ...mapState(['a','b','c']),      }
 }
</script>

...mapState(['a','b','c']), 就相当于以下代码,明显提高了代码编写效率。

 <template>
  <div>{{this.a}}</div> 
  <div>{{this.b}}</div>
</template>
<script>
  export default {
    computed: {
       a(){
          return this.$store.state.a
        },
        b(){
          return this.$store.state.b
        }
        ....
    }
 }
</script>        

注:前面的方法名和获取的属性名是一致的。

7.Module:

实际开发中假设只使用一个stroe,久而久之,sotre中的代码量就会变得非常臃肿。

为了解决这一问题,Vuex 允许我们将 store 分割成多个模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。

官网的此类描述就已经是大白话了,vuex的这个属性也是最好理解的。

但是怎么优美的去配置这个属性呢?请继续往下阅读

二、动态配置vuex.store

1.在store目录下创建一个modules文件夹,里面存放分割的多个模块(module),如下图所示

2.在modules文件夹下创建一个user.js模块(module)

以用户登录为例:

用户通过前端页面提交用户名/密码等信息,提交给后台;获的后台返回的token,并将token存放到vuex中。

为了让初学者更容易理解,简化下user.js中的代码,如下所示:

import { login } from '@/api/user' //引用访问后台的login接口
const state = {
  token: "",
}

const mutations = {
  SET_TOKEN: (state, token) => {
    state.token = token
  }
}

const actions = {
  login({ commit }, userInfo) {
    const { username, password } = userInfo
    
    return new Promise((resolve, reject) => {
      login({ username: username.trim(), password: password }).then(response => {
        commit('SET_TOKEN', data.token)
        resolve()
      }).catch(error => {
        reject(error)
      })

    })
  },
}

export default {
  namespaced: true,//此处定义命名空间
  state,
  mutations,
  actions
}

模块创建完毕,通过1中我们得知modules文件夹下有很多类似的模块,下面我们就将这些模块进行统一配置

3.配置vuex的modules

(1).打开store下的index.js,代码如下

import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
Vue.use(Vuex)
//通过正则表达式获取modules文件夹下的所有js文件
const modulesFiles = require.context('./modules', true, /\.js$/)

//动态配置vuex.store的核心代码-start
//遍历模块文件,将所有的单个模块,汇总成符合vuex规范的modules.
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
  const value = modulesFiles(modulePath)
  modules[moduleName] = value.default
  //控制台打印
  console.log("modulePath",modulePath)    console.log("moduleName",moduleName)
  console.log("value",value)  return modules
}, {})
//动态配置vuex.store的核心代码-end

console.log("modules",modules)  //控制台打印

//vues.store统一配置modules
const store = new Vuex.Store({
  modules,
  getters
})
export default store 

控制台modules打印结果如下,动态配置成功

基础小知识

reduce定义、****reduce应用场景思考

4.通过namespaced属性,在组件中使用actions

在创建的user.js模块中我们声明了命名空间namespaced: true,这个属性使我们能在

项目的各个组件中调用,方式如下:

this.$store.dispatch('user/login', parm)

parm即为传递的参数

注:因为是模块化动态配置的store,避免模块件不同模块命名冲突的问题,故使用

namespaced:true,其中user/login中的user即为模块名字