深入理解vuex2.0 之 modules


Posted in Javascript onNovember 20, 2017

什么是module?

背景:在Vue中State使用是单一状态树结构,应该的所有的状态都放在state里面,如果项目比较复杂,那state是一个很大的对象,store对象也将对变得非常大,难于管理。

module:可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理。

怎么用module?

一般结构

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

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

模块内部的数据:①内部state,模块内部的state是局部的,也就是模块私有的,比如是car.js模块state中的list数据,我们要通过this.$store.state.car.list获取;②内部getter、mutation和action,仍然注册在全局命名空间内,这是为了多模块可以同时响应同一mutation;this.$store.state.car.carGetter的结结果是undefined,而通过this.$store.state.carGetter则可以拿到。

传参:getters====({state(局部状态),getters(全局getters对象),roosState(根状态)});actions====({state(局部状态),commit,roosState(根状态)}).

新建一个项目体验一下,通过vue ?cli新建一个项目vuemodule, 不要忘记安装vuex.

1, 在src 目录下新一个login文件夹,在里面新建index.js 用于存放login 模块的状态。 为了简单起见,我把模块下的state, actions,mutations, getters 全放在index.js文件中。

先简单给它增加一个状态,userName: “sam”

const state = {
  useName: "sam"
};
const mutations = {

};
const actions = {

};
const getters = {

};

// 不要忘记把state, mutations等暴露出去。
export default {
  state,
  mutations,
  actions,
  getters
}

2,在src 目录下,再新建一个 store.js 这是根store, 它通过modules 属性引入 login模块。

import Vue from "vue";
import Vuex from "Vuex";

Vue.use(Vuex);

// 引入login 模块
import login from "./login"

export default new Vuex.Store({
  // 通过modules属性引入login 模块。
  modules: {
    login: login
  }
})

3, 在main.js中引入store, 并注入到vue 根实例中。

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

// 引入store
import store from "./store"

new Vue({
 el: '#app',
 store, // 注入到根实例中。
 render: h => h(App)
})

4,在 app.vue 中通过computed属性获取到login下的state.  这里要注意,在没有modules 的情况下,组件中通过  this.$store.state.属性名  可以获取到,但是有modules 之后,state 被限制到login 的命名空间(模块)下,所以属性名前面必须加模块名(命名空间),组件中通过 this.$store.state.模块名.属性名,在这里是 this.$store.state.login.userName

<template>
 <div id="app">
  <img src="./assets/logo.png">
  <h1>{{useName}}</h1>
 </div>
</template>

<script>
export default {
 // computed属性,从store 中获取状态state,不要忘记login命名空间。
 computed: {
  useName: function() {
   return this.$store.state.login.useName
  }
 }
}
</script>

组件中成功获取到状态。项目目录和展示如下

深入理解vuex2.0 之 modules

4 ,通过actions, mutations 改变名字, 这就涉及到dispatch action, commit mutations, mutations 改变state.

先在login 文件夹 index.js中添加changeName action 和  CHANGE_NAME  mutations.

const mutations = {
  CHANGE_NAME (state, anotherName) {
    state.useName = anotherName;
  }
};

const actions = {
  changeName ({commit},anotherName) {
    commit("CHANGE_NAME", anotherName)
  }
};

在app.vue 中添加一个按钮:<button> change to json</button>, 点击时,dispatch  一个 action. 那在组件中怎么dispatch actions 呢?

在模块中,state 是被限制到模块的命名空间下,需要命名空间才能访问。 但actions 和mutations, 其实还有 getters 却没有被限制,在默认情况下,它们是注册到全局命名空间下的,所谓的注册到全局命名空间下,其实就是我们访问它们的方式和原来没有module 的时候是一样的。比如没有module 的时候,this.$store.dispatch(“actions”), 现在有了modules, actions 也写在了module 下面(changeName 写到了login目录下的index.js中),我们仍然可以这么写,this.$store.dispatch(“changeName”), 组件中的getters, 也是通过 this.$store.getters.module中getters 来获取。

<template>
 <div id="app">
  <img src="./assets/logo.png">
  <h1>{{useName}}</h1>
  <!-- 添加按钮 -->
  <div>
   <button @click="changeName"> change to json</button>
  </div>
 </div>
</template>

<script>
export default {
 // computed属性,从store 中获取状态state,不要忘记login命名空间。
 computed: {
  useName: function() {
   return this.$store.state.login.useName
  }
 },
 methods: {

// 和没有modules的时候一样,同样的方式dispatch action
  changeName() {
   this.$store.dispatch("changeName", "Jason")
  }
 }
}

5, 局部参数

虽然dispatch action和 commit mutations 可以全局使用,但是写在module 中的actions, mutations 和getters, 它们获得的默认参数却不是全局的,都是局部的,被限定在它们所在的模块中的。比如mutations和getters 会获得state 作为第一个默认参数,这个state参数,就是限定在mutations 和getters 所在模块的state对象,login 文件夹下的mutations 和getters 只会获取到当前index.js 中的 state 作为参数 。 actions 会获得一个context 对象作为参数,这个context 对象就是当前module 的实例,module 相当于一个小store.

那么怎样才能获取到根store 中的state 和 getters 呢? Vuex 提供了 rootState, rootGetters 作为module 中  getters 中默认参数, actions中context 对象,也会多了两个属性,context.getters, context. rootState,  这些全局的默认参数,都排在局部参数的后面。

我们在store.js中添加 state, getters: 

export default new Vuex.Store({
  // 通过modules属性引入login 模块。
  modules: {
    login: login
  },

  // 新增state, getters
  state: {
    job: "web"
  },
  getters: {
    jobTitle (state){
      return state.job + "developer"
    }
  }
})

login 目录下的 index.js

const actions = {
  // actions 中的context参数对象多了 rootState 参数
  changeName ({commit, rootState},anotherName) {
    if(rootState.job =="web") {
      commit("CHANGE_NAME", anotherName)
    }
  }
};

const getters = {
  // getters 获取到 rootState, rootGetters 作为参数。
  // rootState和 rootGetter参数顺序不要写反,一定是state在前,getter在后面,这是vuex的默认参数传递顺序, 可以打印出来看一下。
  localJobTitle (state,getters,rootState,rootGetters) { 
    console.log(rootState);
    console.log(rootGetters);
    return rootGetters.jobTitle + " aka " + rootState.job 
  }
};

app.vue 增加h2 展示 loacaJobTitle, 这个同时证明了getters 也是被注册到全局中的。

<template>
 <div id="app">
  <img src="./assets/logo.png">
  <h1>{{useName}}</h1>

  <!-- 增加h2 展示 localJobTitle -->
  <h2>{{localJobTitle}}</h2>
  <!-- 添加按钮 -->
  <div>
   <button @click="changeName"> change to json</button>
  </div>
 </div>
</template>

<script>
import {mapActions, mapState,mapGetters} from "vuex";
export default {
 // computed属性,从store 中获取状态state,不要忘记login命名空间。
 computed: {
  ...mapState({
   useName: state => state.login.useName
  }),

  // mapGeter 直接获得全局注册的getters
  ...mapGetters(["localJobTitle"])
 },
 methods: {
  changeName() {
   this.$store.dispatch("changeName", "Jason")
  }
 }
}
</script>

6, 其实actions, mutations, getters, 也可以限定在当前模块的命名空间中。只要给我们的模块加一个namespaced 属性:

const state = {
  useName: "sam"
};
const mutations = {
  CHANGE_NAME (state, anotherName) {
    state.useName = anotherName;
  }
};
const actions = {
  changeName ({commit, rootState},anotherName) {
    if(rootState.job =="web") {
      commit("CHANGE_NAME", anotherName)
    }
  },
  alertName({state}) {
    alert(state.useName)
  }
};
const getters = {
  localJobTitle (state,getters,rootState,rootGetters) { 
    return rootGetters.jobTitle + " aka " + rootState.job 
  }
};
// namespaced 属性,限定命名空间
export default {
  namespaced:true,
  state,
  mutations,
  actions,
  getters
}

当所有的actions, mutations, getters 都被限定到模块的命名空间下,我们dispatch actions, commit mutations 都需要用到命名空间。如 dispacth("changeName"),  就要变成 dispatch("login/changeName"); getters.localJobTitle 就要变成 getters["login/localJobTitle"]

app.vue 如下:

<template>
 <div id="app">
  <img src="./assets/logo.png">
  <h1 @click ="alertName">{{useName}}</h1>

  <!-- 增加h2 展示 localJobTitle -->
  <h2>{{localJobTitle}}</h2>
  <!-- 添加按钮 -->
  <div>
   <button @click="changeName"> change to json</button>
  </div>
 </div>
</template>

<script>
import {mapActions, mapState,mapGetters} from "vuex";
export default {
 // computed属性,从store 中获取状态state,不要忘记login命名空间。
 computed: {
  ...mapState("login",{
   useName: state => state.useName
  }),

   localJobTitle() {
    return this.$store.getters["login/localJobTitle"]
   }
 },
 methods: {
  changeName() {
   this.$store.dispatch("login/changeName", "Jason")
  },
  alertName() {
   this.$store.dispatch("login/alertName")
  }
 }
}
</script>

有了命名空间之后,mapState, mapGetters, mapActions 函数也都有了一个参数,用于限定命名空间,每二个参数对象或数组中的属性,都映射到了当前命名空间中。

<script>
import {mapActions, mapState,mapGetters} from "vuex";
export default {
 computed: {
  // 对象中的state 和数组中的localJobTitle 都是和login中的参数一一对应。
  ...mapState("login",{
   useName: state => state.useName
  }),
  ...mapGetters("login", ["localJobTitle"])
 },
 methods: {
  changeName() {
   this.$store.dispatch("login/changeName", "Jason")
  },
  ...mapActions('login', ['alertName'])
 }
}
</script>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
基于jquery的一个浮动框(扩展性比较好 )
Aug 27 Javascript
浅谈Javascript事件处理程序的几种方式
Jun 27 Javascript
jquery、js调用iframe父窗口与子窗口元素的方法整理
Jul 31 Javascript
Express实现前端后端通信上传图片之存储数据库(mysql)傻瓜式教程(二)
Dec 10 Javascript
AngularJS定时器的使用与移除操作方法【interval与timeout】
Dec 14 Javascript
Angular在一个页面中使用两个ng-app的方法(二)
Feb 20 Javascript
前端html中jQuery实现对文本的搜索功能并把搜索相关内容显示出来
Nov 14 jQuery
vuex提交state&amp;&amp;实时监听state数据的改变方法
Sep 16 Javascript
Vue-CLI3.x 设置反向代理的方法
Dec 06 Javascript
Layui给switch添加响应事件的例子
Sep 03 Javascript
详细介绍解决vue和jsp结合的方法
Feb 06 Javascript
基于小程序请求接口wx.request封装的类axios请求
Jul 02 Javascript
three.js中文文档学习之如何本地运行详解
Nov 20 #Javascript
AngularJS实现自定义指令及指令配置项的方法
Nov 20 #Javascript
详解webpack + react + react-router 如何实现懒加载
Nov 20 #Javascript
详细分析jsonp的原理和实现方式
Nov 20 #Javascript
three.js中文文档学习之通过模块导入
Nov 20 #Javascript
JS写XSS cookie stealer来窃取密码的步骤详解
Nov 20 #Javascript
浅谈Vue SSR 的 Cookies 问题
Nov 20 #Javascript
You might like
PHP 遍历XP文件夹下所有文件
2008/11/27 PHP
PHP 多进程 解决难题
2009/06/22 PHP
用PHP ob_start()控制浏览器cache、生成html实现代码
2010/02/16 PHP
推荐一款MAC OS X 下php集成开发环境mamp
2014/11/08 PHP
php生成酷炫的四个字符验证码
2016/04/22 PHP
php 使用fopen函数创建、打开文件详解及实例代码
2016/09/24 PHP
php实现跨域提交form表单的方法【2种方法】
2016/10/17 PHP
laravel 之 Eloquent 模型修改器和序列化示例
2019/10/17 PHP
PHP 对象继承原理与简单用法示例
2020/04/21 PHP
js读取被点击次数的简单实例(从数据库中读取)
2014/03/07 Javascript
解决自定义$(id)的方法与jquery选择器$冲突的问题
2014/06/14 Javascript
jquery插件pagination实现无刷新ajax分页
2015/09/30 Javascript
Node.js中路径处理模块path详解
2016/11/14 Javascript
EasyUI学习之DataGird分页显示数据
2016/12/29 Javascript
jQuery选择器中的特殊符号处理方法
2017/09/08 jQuery
vuex实现登录状态的存储,未登录状态不允许浏览的方法
2018/03/09 Javascript
jQuery+ajax读取json数据并按照价格排序示例
2018/03/28 jQuery
jQuery实现开关灯效果
2020/08/02 jQuery
Python编写检测数据库SA用户的方法
2014/07/11 Python
python格式化字符串实例总结
2014/09/28 Python
Python压缩和解压缩zip文件
2015/02/14 Python
Python计算一个文件里字数的方法
2015/06/15 Python
详解python 拆包可迭代数据如tuple, list
2017/12/29 Python
Python+matplotlib+numpy实现在不同平面的二维条形图
2018/01/02 Python
pyqt5简介及安装方法介绍
2018/01/31 Python
Python实现朴素贝叶斯分类器的方法详解
2018/07/04 Python
Python中zip()函数的解释和可视化(实例详解)
2020/02/16 Python
CSS3 Backgrounds属性相关介绍
2011/05/11 HTML / CSS
如何在网站上添加谷歌定位信息
2016/04/16 HTML / CSS
HTML5等待加载动画效果
2017/07/27 HTML / CSS
联想德国官网:Lenovo Germany
2018/07/04 全球购物
娇韵诗俄罗斯官方网站:Clarins俄罗斯
2020/10/03 全球购物
房产转让协议书
2014/04/11 职场文书
同意报考公务员证明
2015/06/17 职场文书
2015年学校消防安全工作总结
2015/10/14 职场文书
Python 如何实现文件自动去重
2021/06/02 Python