Vue全家桶Vuex

文章目录

  • 一、Vuex是什么?
  • 二、Vuex的安装及使用
    • 1.安装
    • 2.使用
    • 3.配置
    • 4.state
      • 4.1. 在main.js中创建Vuex实例
      • 4.2. 如何获取state?
        • 4.2.1.mapState辅助函数
    • 5.getter
      • 5.1.mapGetters辅助函数
    • 6.mutation
      • 6.1.mapMutaions辅助函数
    • 7.action
      • 7.1.mapActions辅助函数
    • 8.module模块化和命名空间


一、Vuex是什么?

       在实际开发中经常会遇到多组件访问同一数据的情况,而且需要根据数据的变化做出响应,而这些组件之间并不是父子组件这种简单的关系,在这种情况下,就需要一个全局的状态管理方案。在Vue中,官方推荐使用Vuex。
       在项目中应用的场景非常广泛,比如实现购物车,会员登录验证等功能,开发大型项目需要用Vuex来做数据流的管理。

二、Vuex的安装及使用

1.安装

可以使用CDN的方式安装,代码如下:

<!--引用最新版本-->
<script src=”https://unpkg.com/vuex”>
<!--引用指定版本-->
<script src=”https://unpkg.com/[email protected]”>

如果使用模块化开发,则使用NPM方法安装,输入并执行以下命令:

npm install --save vuex

2.使用

每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同:

  1. Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。

  2. 不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

3.配置

在Vue的脚手架项目中使用,在src/main.js文件中的代码如下:

//导入Vuex
import Vuex from "vuex";
//安装插件
Vue.use(Vuex);
//实例化Vuex并调用Store方法
let store=new Vuex.Store({});
new Vue({
  router,
  store,//注册store
  render: h => {return h(App)},
}).$mount('#app')

4.state

Vuex使用单一状态树,用一个对象就包含了全部的应用层级状态。作为唯一的数据源而存在,这也意味着,每个应用将仅仅包含一个store实例。

4.1. 在main.js中创建Vuex实例

let store=new Vuex.Store({
    //状态数据放在state选项中
    state:{
      count:0
    }
});

4.2. 如何获取state?

//1.标签中获取
<template>
    <div class="page">
        <!--在视图中访问store实例中state选项的count属性值-->
        计数器:{{$store.state.count}}
    </div>
</template>

//2.js中
<script>
    export default {
        name: "home",
        created(){
            //在js中访问store实例中state选项的count属性值
            console.log(this.$store.state.count);
        }
    }
</script>

4.2.1.mapState辅助函数

当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性。

<template>
    <div class="page">
        <!--在视图中访问store实例中state选项的count属性值-->
        计数器:{{count}}
    </div>
</template>


import {mapState} from "vuex";
computed:{
            //使用扩展运算符提取mapState函数返回的对象属性
            ...mapState({
                //方式1:箭头函数可使代码更简练(推荐使用)
                count:state=>state.count,
                //方式2:传字符串参数count等同于 `state => state.count`
                count:"count",
                //方式3:为了能够使用this获取局部状态,可以使用常规函数
                count(state){
                    return state.count
                }
                方式4:使用数组的方式获取state存放的数据
            	...mapState(["count"])
            })
        }

5.getter

它与计算属性类似相当于computed(只不过这是全局的),有时候我们需要从store中的state中派生出一些状态,例如对列表进行过滤并计数:

// 1.main.js创建的Vuex实例
let store=new Vuex.Store({
    state:{
        users:[
            {id:1,name:"张三",age:18},
            {id:2,name:"李四",age:20},
            {id:3,name:"王五",age:22},
            {id:4,name:"赵六",age:25}
        ]
    },

    getters:{
        /*
        第一个参数:本模块中的state
        第二个参数:其他 getter
        第三个参数:所有模块的state
        */
        getUsers(state,getters,rootState){
            //筛选age大于18的数据
            let users=state.users.filter((res)=>{
                return res.age>18
            })
            return users;
        }
    }
});

//2.在需要的组件中使用
<template>
    <div class="page">
        <ul>
            <li v-for="item in $store.getters.getUsers" :key="item.id">
                {{item.name}}--{{item.age}}
            </li>
        </ul>
    </div>
</template>
<script>
    export default {
        name: "home",
        created() {
            //在js中访问getter
            console.log(this.$store.getters.getUsers)
        }
    }
</script>

5.1.mapGetters辅助函数

<template>
    <div class="page">
        <ul>
            <li v-for="item in getUsers" :key="item.id">
                {{item.name}}--{{item.age}}
            </li>
        </ul>
    </div>
</template>

<script>
    import {mapGetters} from "vuex";
    export default {
        name: "home",
        computed:{
            //使用扩展运算符提取mapGetters函数返回的对象属性
            //方式一:数组字符串形式
            ...mapGetters(["getUsers"]),
            //方式二:对象形式(推荐使用)
            ...mapGetters({
                getUsers:"getUsers"
            })
        }
    }
</script>

6.mutation

如果想要改变state中的count的值唯一方法是提交 mutation。Vuex中的 mutation 非常类似于事件:每个mutation都有一个字符串的事件类型(type)和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受state作为第一个参数。

// 1.main.js 中创建vuex实例
let store=new Vuex.Store({
    //状态数据放在state选项中
    state:{
      count:0
    },
    mutations:{
      //自定义inc方法
     inc(state,payload){
        state.count+=payload.amount;
      }
    }
});


//2.在需要的组件中使用
<template>
    <div class="page">
        <!--在视图中访问store实例中state选项的count属性值-->
        计数器:{{$store.state.count}} <button type="button" @click="increment">+</button>
    </div>
</template>
<script>
    export default {
        name: "home",
        methods:{
            increment(){
                //使用commit调用store实例中mutations中的inc方法 载荷提交(推荐使用)
              this.$store.commit("inc",{amount:10});
              //对象风格的提交
              this.$store.commit({
                     type:"inc",
                     amount:10
                });
              }
          }

使用常量替代Mutation事件类型(多人开发时可以使用这种形式):

1.首先在src文件夹下创建store文件夹,在该文件夹下创建mutation-types.js文件,该文件的代码如下:

//1.导出一个名为INC的常量值为“inc
export const INC="inc";

2.导入一个名为INC的常量值为“inc”,在src/main.js文件中的代码如下:

//导入INC常量
import {INC} from "./store/mutation-types";
 mutations:{
      //使用ES6风格的计算属性命名功能来使用一个常量作为函数名
      [INC](state,payload){
        state.count+=payload.amount;
      }
    }

6.1.mapMutaions辅助函数

在实际开发中,大多数都使用辅助函数的方式提交mutation。

<template>
    <div class="page">
        <!--在视图中访问store实例中state选项的count属性值-->
        计数器:{{count}} <button type="button" @click="increment">+</button>
    </div>
</template>

import {mapMutations} from "vuex";
methods:{
            //使用ES6扩展运算符提取mapMutations函数返回的对象属性
            //方式一(推荐):使用对象的方式,将this.inc()映射为this.$store.commit("inc")
            ...mapMutations({
                inc:"inc"
            }),
            //方式二:使用字符串数组方式,将this.inc()映射为this.$store.commit("inc")
            ...mapMutations(["inc"]),
            increment(){
                //这里的inc方法就是上面...mapMutations(["inc"])中的inc
                this.inc({amount:10});
            }
        },
注意:一条重要的原则就是要记住 mutation必须是同步函数。

如果使用异步函数比如setTimeout,代码执行上不会有任何问题。只是在调试上变得困难,比如我们正在debug一个应用并且观察 devtool 中的 mutation 日志。

devtools是一款基于chrome游览器的插件,用于调试Vue应用,可以去百度搜索vue-devtools进行下载安装,使用非常简单,这里就不在做详细的介绍,因为在开发中没有必要非用vue-devtools调试。

7.action

Action类似 mutation,不同在于,Action提交的是 mutation,而不是直接变更状态,Action可以包含任意的异步操作。

//1.实例化Vuex并调用store方法
let store=new Vuex.Store({
    //状态数据放在state选项中
    state:{
      count:0
    },
   mutations:{
      inc(state,payload){
          //接收action分发的payload
         state.count+=payload.amount;
      }
    },
   actions:{
      asyncInc({commit},payload){
            //将接收的分发payload,组装新的对象形式的值{amount:payload.amount}使用commit提交给mutation
           commit("inc",{amount:payload.amount})
        }
    }
});
// 2.使用
<template>
    <div class="page">
        <!--在视图中访问store实例中state选项的count属性值-->
        计数器:{{count}} <button type="button" @click="increment">+</button>
    </div>
</template>

methods:{
       increment(){
          //以载荷形式分发
           this.$store.dispatch("asyncInc",{amount:10});

           //以对象形式分发
           this.$store.dispatch({
                 type:"asyncInc",
                 amount:10
            });           
        }
  },

7.1.mapActions辅助函数

同样action和mutation一样也有辅助函数使用方式也一样,在实际开发中我们使用辅助函数来进行分发。

<template>
    <div class="page">
        <div class="page">
            <!--在视图中访问store实例中state选项的count属性值-->
            计数器:{{count}} <button type="button" @click="increment">+</button>
        </div>
    </div>
</template>

import {mapActions} from "vuex";
methods:{
            //使用扩展运算符ES6扩展运算符提取mapActions函数返回的对象属性
            //方式一:使用对象的方式,将this.asyncInc()映射为this.$store.dispatch("asyncInc")
            ...mapActions({
                asyncInc:"asyncInc"
            }),
            //方式二:使用字符串数组方式,将this.asyncInc()映射为this.$store.dispatch("asyncInc")
            ...mapActions(["asyncInc"]),
            increment(){
                //这里的asyncInc方法就是上面...mapActions(["asyncInc"])中的inc
                this.asyncInc({amount:10})
            }
        },

8.module模块化和命名空间

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块,从上至下进行同样方式的分割,例如:

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}


const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的,这样使得多个模块能够对同一mutation或action作出响应。 如果希望模块具有更高的封装度和复用性,可以通过添加namespaced: true的方式使其成为带命名空间的模块。当模块被注册后,它的所有getter、action 及 mutation 都会自动根据模块注册的路径调整命名。

let counter={
    namespaced:true,//开启支持命名空间
};

你可能感兴趣的:(vue.js,javascript,前端)