Vue教程-7-Vuex

目录

1.概念

1.1.官网地址

1.2.Vuex与Vue之间事件发布

1.3.什么状态适合共享

1.4.Vuex组成

1.5.Vuex安装

2.State

3.Getters

4.Mutations

5.Actions

6.Modules

7.项目代码

8.项目目录优化改造


1.概念

Vuex是一个专为Vue.js应用程序而开发的状态管理模式,其采用集中式存储管理应用的所有组件状态,并以相应的规则来保证状态以一种可预测的方式发生变化,同时Vuex也集成到Vue的官方测试工具devtools extension,提供了一系列对应的测试功能;

通俗来讲,就是N个组件共享同一个变量,类似于多线程同步的场景,当这个变量发生变化后,凡是引用该变量的N个组件都会自动进行刷新操作,这里官网的一个图片比较形象:

当State发生变化,然后Vuex刷新到View上,然后Vue监听View上的变化,然后再修改State;

1.1.官网地址

https://vuex.vuejs.org/zh/

1.2.Vuex与Vue之间事件发布

State变化后,Vue.render渲染到Vue组件,当Vue组件发生事件后,通过dispatch分发到Vuex.actions,然后再由actions提交到mutations中,再由mutations挂载到state;

1.3.什么状态适合共享

多个组件需要共享的状态,例如:用户登录状态、用户名称、购物车、商品收藏等;

1.4.Vuex组成

state、getters、mutations、actions、modules

1.5.Vuex安装

npm install vuex --save

2.State

存放各种各样的“状态”,这里state又被叫做“单一状态树”,通俗来讲,就是state就是唯一数据源,确保数据源的唯一性,同时官方建议整个前段工程中,Vuex.Store实例也只有一个,避免多个Vuex.Store同时存在;(可以理解为Vue的data)

3.Getters

类似于Vue组件的计算属性,通俗来讲,如果state中的属性无法直接使用,例如:需要对属性进行加减乘数运算、或者拼接、分割运算等,此时就需要getters;(可以理解为Vue的computed)

这里有几个注意事项/使用场景:

①getters中定义的方法,其默认带有state参数,该state参数就是该实例的state对应的对象;

②以“getters”对象为参数,来传入自定义方法中;

③调用方负责传递参数;

4.Mutations

通过官网的说明,我们可以得知更新Vuex的state唯一方式:提交mutaion;

知识点1:commit提交mutations有2种方式:普通方式、type方式提交;

知识点2:当type方式commit的时候,所有的参数都会被Vuex当做对象来接受,Vuex称之为:载荷payload;

知识点3:鉴于mutations负责修改state的,Vuex中state是响应式的,当state中的数据发生改变时,Vue组件会自动更新;要想达到“响应式”的效果,必须遵循如下规则:

①提前在state中初始化所需的一切属性;

②当给state对象新增属性时,使用下面方式添加:

使用Vue.set(obj,’newProp’,newPropValue),或者,用新对象对旧对象重新赋值;(CLI4中,不用这2种方式,直接新增属性也能达到响应式效果)

知识点4:mutations中定义的方法,其默认带有state参数,该state参数就是该实例的state对应的对象;

知识点5:Vuex官方建议使用“常量类型”来为方法命名;

知识点6:Vuex要求mutations中的方法必须是同步方法;当我们使用devtools时,可以用devtools捕获mutation快照,如果是异步操作的话,devtools就不能很好的跟踪这个操作在什么时候会被完成;

(可以把mutations理解为组件的methods)

5.Actions

正是由于mutations无法编写异步方法,为了解决异步方法问题,这里发明了actions;

由于actions中定义的是异步任务,比较常见的就是下载APP,例如手机一边下载数据,一边更新进度条来告诉用户,当前的下载进度;

知识点1;相比getters/mutations方法,actions中定义的方法,其第一个参数是context;

知识点2;这里可以使用new Promise来优雅的实现类似这种一边下载,一边更新UI进度条的效果;

6.Modules

由于整个前端工程就一个Vuex实例,这就意味着很多内容都要写在state、getters、mutations等,例如:家电模块的state/getters/mutations等、床上用品模块的state/getters/mutations等、个人用品模块的state/getters/mutations等;

这就意味着,在一个state、getters、mutations标签内部会包含各种业务模块的信息,这就意味着一方面代码量庞大,另外一方面各种业务混杂;

为了解决这种混杂的问题,于是发明了modules;modules组成内容如下:

modules:{

  模块A: {

     state:{},

     mutations:{},

     actions:{},

     getters:{},

     modules:{}

},

模块B: {

     state:{},

     mutations:{},

     actions:{},

     getters:{},

     modules:{}

},

......................

}

知识点1:module子模块mutations/getters方法参数中的state指的是当前子模块的state对象;

知识点2:module子模块actions方法参数中的context指的是当前子模块对象;

知识点3:要想访问上级Vuex对象中的内容,则可以通过context.rootGetters和context.rootState来获取,下面是打印的context对象:

7.项目代码

①新建src/store目录,下面新建对应的文件:

mutations-types.js

// 定义常量类型,这样就可以保证整个前端工程所引用的方法名都是统一的,不用每次都修改多个文件

 

let INCREMENT = 'increment';

let DECREMENT = 'decrement';

let INCREMENTCOUNT = 'incrementCount';

let INCREMENTCOUNT2 = 'incrementCount2';

let UPDATEINFO = 'updateInfo';

let AUPDATEINFO = 'aUpdateInfo';

let UPDATEMODULESINFO = 'updateModulesInfo';

let UPDATEMODULESINFOASYNC = 'updateModulesInfoAsync';

 

 

 

export {

  INCREMENT,DECREMENT,INCREMENTCOUNT,INCREMENTCOUNT2,UPDATEINFO,AUPDATEINFO,UPDATEMODULESINFO,UPDATEMODULESINFOASYNC

}

index.vue

<template>

 

</template>

 

<script>

  // 注册Vuex

  import Vue from 'vue'

  import Vuex from 'vuex'

  import * as MutationsType from './mutations-types'

 

  Vue.use(Vuex);

 

  const carModule = {

    state:{

      type: '奥迪',

      name: 'A8',

      size: 2.0,

      weight: '2.0T'

    },

    getters:{

      // 这里的state,指的是carModule的state

      carName1(state){

        return state.type + state.name + '-carName1';

      },

      // 这里的state,指的是carModule的state,这里的getters,指的是carModule的getters

      carName2(state,getters){

        return getters.carName1 + '-carName2';

      },

      // 这里的state,指的是carModule的state,这里的getters,指的是carModule的getters,这里的rootGetters,指的是Vuex.Store的getters

      carName3(state,getters,rootState){

        // console.log(rootState);

        return getters.carName2 + rootState.firstname + rootState.lastname + '-carName3';

      }

    },

    mutations:{

      // 这里的state,指的是carModule的state

      [MutationsType.UPDATEMODULESINFO](state,name){

        state.type = name;

      }

    },

    actions:{

      // 这里的context指的是carMoule

      [MutationsType.UPDATEMODULESINFOASYNC](context,payload){

        console.log(context);

        console.log(context.rootGetters.username);

        console.log(payload);

        return new Promise((resolve, reject) => {

          setTimeout(() => {

            context.commit(MutationsType.UPDATEMODULESINFO,payload.type.name);

            console.log('carModule-Promise方式异步任务执行完毕,准备回调');

            resolve('carModule-Promise方式异步任务回调');

          },1000);

        });

      }

    },

    modules:{}

  }

 

  export default new Vuex.Store({

    state: {

      count: 100,

      firstname: '张',

      lastname: '三'

    },

    mutations: {

      // mutations中定义的方法,其默认带有state参数,该state参数就是该实例的state对应的对象

      // 这里使用常量类型

      [MutationsType.INCREMENT](state){

        state.count++;

      },

      // 这里使用常量类型

      [MutationsType.DECREMENT](state){

        state.count--;

      },

      // 调用方传递参数,这种调用方传递的参数称为载荷(payload),如果传递的参数比较多,可以先把参数组装成对象,然后把对象传递进来

      // 这里使用常量类型

      [MutationsType.INCREMENTCOUNT](state,count){

        state.count += count;

      },

      // 提交风格2:调用方使用type风格进行commit的时候,Vuex会把参数看做成一个对象,因此,想要获取对象中的属性就必须使用"."运算符

      // 这里使用常量类型

      [MutationsType.INCREMENTCOUNT2](state,payload){

        state.count += payload.count;

      },

      [MutationsType.UPDATEINFO](state,name){

        state.firstname = name;

      }

    },

    actions: {

      // 这里定义的方法,默认参数都是context,而不是之前的state

      // 这里,通过调用方传入一个object,而object的success和fail属性都是函数,来实现通知调用方actions的执行情况

      // [MutationsType.AUPDATEINFO](context,payload){

      //   setTimeout(() => {

      //     context.commit(MutationsType.UPDATEINFO,payload.message.name);

      //     console.log(payload.success);

      //     console.log(payload.fail);

      //   },2000);

      // }

      // 这里进行了改进,相比用object,这里用了Promise.then方式来回调

      [MutationsType.AUPDATEINFO](context,payload){

          return new Promise((resolve, reject) => {

            setTimeout(() => {

              context.commit(MutationsType.UPDATEINFO,payload.message.name);

              console.log('Promise方式异步任务执行完毕,准备回调');

              resolve('Promise方式异步任务回调');

            },1000);

          });

      }

    },

    getters: {

      // getters中定义的方法,其默认带有state参数,该state参数就是该实例的state对应的对象

      username(state){

        return state.firstname + state.lastname;

      },

      // 这里以“getters”对象为参数,来传入自定义方法中

      usernameLength(state,getters){

        return getters.username.length;

      },

      // 调用方负责传递参数

      usernameByZhang(state,getters){

        // return function (str) {

        //   return getters.username.startsWith(str);

        // }

        // 使用箭头函数进行简写

        return str => getters.username.startsWith(str);

      }

    },

    modules: {

      carModule

    }

  });

</script>

 

<style scoped>

 

</style>

②在入口main.js中挂载Vuex:

main.js

import Vue from 'vue'

import App from './App'

import store from './store'

 

Vue.config.productionTip = false

 

/* 这里记得挂载store,否则this.$store失败,同时注意与import中大小写一致 */

new Vue({

  el: '#app',

  store,

  render: h => h(App)

})

③在自定义component中使用Vuex:

component1.vue

<template>

    <div>

      <h1>下面是modules模块的内容</h1>

      <h2>{{$store.state.carModule.name}}</h2>

      <h2>{{$store.getters.carName1}}</h2>

      <h2>{{$store.getters.carName2}}</h2>

      <h2>{{$store.getters.carName3}}</h2>

      <button @click="updateType('BMW')">更新modules.carModule中的type(同步修改)</button>

      <button @click="updateTypeAsyn('BMW')">更新modules.carModule中的type(异步修改)</button>

      <h2>{{message}}</h2>

      <h2>{{$store.state.count}}</h2>

      <h2>{{$store.getters.username}}</h2>

      <h2>{{$store.getters.usernameLength}}</h2>

      <h2>{{$store.getters.usernameByZhang('张')}}</h2>

      <button @click="addition">++</button>

      <button @click="addCount(5)">+5</button>

      <button @click="addCount2(5)">+5</button>

      <button @click="subtraction">--</button>

      <button @click="aUpdate('马六')">更新state中的firstname</button>

    </div>

</template>

 

<script>

 

  import * as MutationsType from '../store/mutations-types'

 

    export default {

        name: "component1",

        data(){

          return {

            message: '------------这是自定义组件1------------'

          }

        },

        methods: {

          addition(){

            // 这里使用常量类型

            this.$store.commit(MutationsType.INCREMENT);

          },

          subtraction(){

            // 这里使用常量类型

            this.$store.commit(MutationsType.DECREMENT);

          },

          addCount(count){

            // 提交风格1:调用方传递参数

            // 这里使用常量类型

            this.$store.commit(MutationsType.INCREMENTCOUNT,count);

          },

          addCount2(count){

            // 提交风格2:调用方传递参数

            // 这里使用常量类型

            this.$store.commit({

              type: MutationsType.INCREMENTCOUNT2,

              count

            });

          },

          // 这里是通过object内部封装函数的方式来实现回调actions

          // aUpdate(msg){

          //   this.$store.dispatch(MutationsType.AUPDATEINFO,{

          //     message: {name:msg},

          //     success: () => console.log('操作成功'),

          //     fail: () => console.log('操作失败')

          //   });

          // }

          // 这里进行了改进,相比用object,这里用了Promise.then方式来回调;

          aUpdate(msg){

            this.$store.dispatch(MutationsType.AUPDATEINFO,{

              message: {name:msg}

            }).then(data => console.log('回调结束,返回值是:' + data),err => console.log(err));

          },

          updateType(name){

            // 这里,Vuex会遍历所有的mutations,直到找到一个方法名与MutationsType.UPDATEMODULESINFO一致的为止,不管其是位于modules中,还是Vuex.Store中

            this.$store.commit(MutationsType.UPDATEMODULESINFO,name);

          },

          updateTypeAsyn(name){

            // 这里,Vuex会遍历所有的actions,直到找到一个方法名与MutationsType.UPDATEMODULESINFOASYNC一致的为止,不管其是位于modules中,还是Vuex.Store中

            this.$store.dispatch(MutationsType.UPDATEMODULESINFOASYNC,{

              type: {name:name}

            })

              .then(data => console.log('carModule-回调结束,返回值是:' + data),err => console.log(err));

          }

        }

    }

</script>

 

<style scoped>

 

</style>

App.vue

<template>

  <div id="app">

    <h1>下面是modules模块的内容</h1>

    <h2>{{$store.state.carModule.name}}</h2>

    <h2>{{$store.getters.carName1}}</h2>

    <h2>{{$store.getters.carName2}}</h2>

    <h2>{{$store.getters.carName3}}</h2>

    <button @click="updateType('BMW')">更新modules.carModule中的type(同步修改)</button>

    <button @click="updateTypeAsyn('BMW')">更新modules.carModule中的type(异步修改)</button>

    <h2>{{message}}</h2>

    <h2>{{$store.state.count}}</h2>

    <h2>{{$store.getters.username}}</h2>

    <h2>{{$store.getters.usernameLength}}</h2>

    <h2>{{$store.getters.usernameByZhang('张')}}</h2>

    <button @click="addition">++</button>

    <button @click="addCount(5)">+5</button>

    <button @click="addCount2(5)">+5</button>

    <button @click="subtraction">--</button>

    <button @click="aUpdate('王五')">更新state中的firstname</button>

    <component1></component1>

  </div>

</template>

 

<script>

  import component1 from './components/component1'

 

  import * as MutationsType from './store/mutations-types'

 

  export default {

    name: 'App',

    data(){

      return {

        message: '------------这是App组件------------'

      }

    },

    components:{

      component1

    },

    methods: {

      addition(){

        // 这里使用常量类型

        this.$store.commit(MutationsType.INCREMENT);

      },

      subtraction(){

        // 这里使用常量类型

        this.$store.commit(MutationsType.DECREMENT);

      },

      addCount(count){

        // 调用方传递参数

        // 这里使用常量类型

        this.$store.commit(MutationsType.INCREMENTCOUNT,count);

      },

      addCount2(count){

        // 提交风格2:调用方传递参数

        // 这里使用常量类型

        this.$store.commit({

          type: MutationsType.INCREMENTCOUNT2,

          count

        });

      },

      // 这里是通过object内部封装函数的方式来实现回调actions

      // aUpdate(msg){

      //   this.$store.dispatch(MutationsType.AUPDATEINFO,{

      //     message: {name:msg},

      //     success: () => console.log('操作成功'),

      //     fail: () => console.log('操作失败')

      //   });

      // }

      // 这里进行了改进,相比用object,这里用了Promise.then方式来回调;

      aUpdate(msg){

        this.$store.dispatch(MutationsType.AUPDATEINFO,{

          message: {name:msg}

        }).then(data => console.log('回调结束,返回值是:' + data),err => console.log(err));

      },

      updateType(name){

        // 这里,Vuex会遍历所有的mutations,直到找到一个方法名与MutationsType.UPDATEMODULESINFO一致的为止,不管其是位于modules中,还是Vuex.Store中

        this.$store.commit(MutationsType.UPDATEMODULESINFO,name);

      },

      updateTypeAsyn(name){

        // 这里,Vuex会遍历所有的actions,直到找到一个方法名与MutationsType.UPDATEMODULESINFOASYNC一致的为止,不管其是位于modules中,还是Vuex.Store中

        this.$store.dispatch(MutationsType.UPDATEMODULESINFOASYNC,{

          type: {name:name}

        })

          .then(data => console.log('carModule-回调结束,返回值是:' + data),err => console.log(err));

      }

    }

  }

</script>

 

<style>

</style>

8.项目目录优化改造

一个Vuex有getters、mutations、actons、modules、state对象,可以把这些对象单独抽取成一个js文件,然后统一import即可,更新后的目录结构如下:

下面是各个抽取后的文件内容:

state.js

export default {

  count: 100,

  firstname: '张',

  lastname: '三'

}

mutations.js

import * as MutationsType from "./mutations-types";

 

export default {

  // mutations中定义的方法,其默认带有state参数,该state参数就是该实例的state对应的对象

  // 这里使用常量类型

  [MutationsType.INCREMENT](state){

    state.count++;

  },

  // 这里使用常量类型

  [MutationsType.DECREMENT](state){

    state.count--;

  },

  // 调用方传递参数,这种调用方传递的参数称为载荷(payload),如果传递的参数比较多,可以先把参数组装成对象,然后把对象传递进来

  // 这里使用常量类型

  [MutationsType.INCREMENTCOUNT](state,count){

    state.count += count;

  },

  // 提交风格2:调用方使用type风格进行commit的时候,Vuex会把参数看做成一个对象,因此,想要获取对象中的属性就必须使用"."运算符

  // 这里使用常量类型

  [MutationsType.INCREMENTCOUNT2](state,payload){

    state.count += payload.count;

  },

  [MutationsType.UPDATEINFO](state,name){

    state.firstname = name;

  }

}

actions.js

import * as MutationsType from "./mutations-types";

 

export  default {

  // 这里定义的方法,默认参数都是context,而不是之前的state

  // 这里,通过调用方传入一个object,而object的success和fail属性都是函数,来实现通知调用方actions的执行情况

  // [MutationsType.AUPDATEINFO](context,payload){

  //   setTimeout(() => {

  //     context.commit(MutationsType.UPDATEINFO,payload.message.name);

  //     console.log(payload.success);

  //     console.log(payload.fail);

  //   },2000);

  // }

  // 这里进行了改进,相比用object,这里用了Promise.then方式来回调

  [MutationsType.AUPDATEINFO](context,payload){

    return new Promise((resolve, reject) => {

      setTimeout(() => {

        context.commit(MutationsType.UPDATEINFO,payload.message.name);

        console.log('Promise方式异步任务执行完毕,准备回调');

        resolve('Promise方式异步任务回调');

      },1000);

    });

  }

}

getters.js

export default {

  // getters中定义的方法,其默认带有state参数,该state参数就是该实例的state对应的对象

  username(state){

    return state.firstname + state.lastname;

  },

  // 这里以“getters”对象为参数,来传入自定义方法中

  usernameLength(state,getters){

    return getters.username.length;

  },

  // 调用方负责传递参数

  usernameByZhang(state,getters){

    // return function (str) {

    //   return getters.username.startsWith(str);

    // }

    // 使用箭头函数进行简写

    return str => getters.username.startsWith(str);

  }

}

Src/store/modules/carModule.js

import * as MutationsType from "../mutations-types";

 

export default {

  state:{

    type: '奥迪',

    name: 'A8',

    size: 2.0,

    weight: '2.0T'

  },

  getters:{

    // 这里的state,指的是carModule的state

    carName1(state){

      return state.type + state.name + '-carName1';

    },

    // 这里的state,指的是carModule的state,这里的getters,指的是carModule的getters

    carName2(state,getters){

      return getters.carName1 + '-carName2';

    },

    // 这里的state,指的是carModule的state,这里的getters,指的是carModule的getters,这里的rootGetters,指的是Vuex.Store的getters

    carName3(state,getters,rootState){

      // console.log(rootState);

      return getters.carName2 + rootState.firstname + rootState.lastname + '-carName3';

    }

  },

  mutations:{

    // 这里的state,指的是carModule的state

    [MutationsType.UPDATEMODULESINFO](state,name){

      state.type = name;

    }

  },

  actions:{

    // 这里的context指的是carMoule

    [MutationsType.UPDATEMODULESINFOASYNC](context,payload){

      console.log(context);

      console.log(context.rootGetters.username);

      console.log(payload);

      return new Promise((resolve, reject) => {

        setTimeout(() => {

          context.commit(MutationsType.UPDATEMODULESINFO,payload.type.name);

          console.log('carModule-Promise方式异步任务执行完毕,准备回调');

          resolve('carModule-Promise方式异步任务回调');

        },1000);

      });

    }

  },

  modules:{}

}

最后是入口文件index.vue

<template>

 

</template>

 

<script>

  // 注册Vuex

  import Vue from 'vue'

  import Vuex from 'vuex'

  import * as MutationsType from './mutations-types'

  import getters from './getters'

  import mutations from './mutations'

  import actions from './actions'

  import state from './state'

  import carModule from './modules/carModule'

 

  Vue.use(Vuex);

 

  export default new Vuex.Store({

    state,

    mutations,

    actions,

    getters,

    modules: {

      carModule

    }

  });

</script>

 

<style scoped>

 

</style>

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值