关于Vue.js 2.0的Vuex 2.0 你需要更新的知识库


Posted in Javascript onNovember 30, 2016

应用结构

实际上,Vuex 在怎么组织你的代码结构上面没有任何限制,相反,它强制规定了一系列高级的原则:

1、应用级的状态集中放在 store 中。

2、改变状态的唯一方式是提交mutations,这是个同步的事务。

3、异步逻辑应该封装在action 中。

只要你遵循这些规则,怎么构建你的项目的结构就取决于你了。如果你的 store 文件非常大,仅仅拆分成 action、mutation 和 getter 多个文件即可。

对于稍微复杂点的应用,我们可能都需要用到模块。下面是一个简单的项目架构:

├── index.html
├── main.js
├── api
│   └── ... # 这里发起 API 请求
├── components
│   ├── App.vue
│   └── ...
└── store
    ├── index.js          # 组合 modules 、export store
    ├── actions.js        # 根 action
    ├── mutations.js      # 根 mutations
    └── modules
        ├── cart.js       # cart 模块
        └── products.js   # products 模块

关于更多,查看 购物车实例。

Modules

由于使用了单一状态树,应用的所有状态都包含在一个大对象内。但是,随着我们应用规模的不断增长,这个Store变得非常臃肿。

为了解决这个问题,Vuex 允许我们把 store 分 module(模块)。每一个模块包含各自的状态、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's state
store.state.b // -> moduleB's state

模块本地状态

模块的 mutations 和 getters方法第一个接收参数是模块的本地状态。

const moduleA = {
 state: { count: 0 },
 mutations: {
 increment: (state) {
  // state 是模块本地的状态。
  state.count++
 }
 },

 getters: {
 doubleCount (state) {
  return state.count * 2
 }
 }
}

相似地,在模块的 actions 中,context.state 暴露的是本地状态, context.rootState暴露的才是根状态。

const moduleA = {
 // ...
 actions: {
 incrementIfOdd ({ state, commit }) {
  if (state.count % 2 === 1) {
  commit('increment')
  }
 }
 }
}

在模块的 getters 内,根状态也会作为第三个参数暴露。

const moduleA = {
 // ...
 getters: {
 sumWithRootCount (state, getters, rootState) {
  return state.count + rootState.count
 }
 }
}

命名空间

要注意,模块内的 actions、mutations 以及 getters 依然注册在全局命名空间内 —— 这就会让多个模块响应同一种 mutation/action 类型。你可以在模块的名称中加入前缀或者后缀来设定命名空间,从而避免命名冲突。如果你的 Vuex 模块是一个可复用的,执行环境也未知的,那你就应该这么干了。距离,我们想要创建一个 todos 模块:

// types.js

// 定义 getter、 action 和 mutation 的常量名称
// 并且在模块名称上加上 `todos` 前缀 
export const DONE_COUNT = 'todos/DONE_COUNT'
export const FETCH_ALL = 'todos/FETCH_ALL'
export const TOGGLE_DONE = 'todos/TOGGLE_DONE'
// modules/todos.js
import * as types from '../types'

// 用带前缀的名称来定义 getters, actions and mutations 
const todosModule = {
 state: { todos: [] },

 getters: {
 [types.DONE_COUNT] (state) {
  // ...
 }
 },

 actions: {
 [types.FETCH_ALL] (context, payload) {
  // ...
 }
 },

 mutations: {
 [types.TOGGLE_DONE] (state, payload) {
  // ...
 }
 }
}

注册动态模块

你可以用 store.registerModule 方法在 store 创建之后注册一个模块:

store.registerModule('myModule', {
 // ...
})

模块的 store.state.myModule 暴露为模块的状态。

其他的 Vue 插件可以为应用的 store 附加一个模块,然后通过动态注册就可以使用 Vuex 的状态管理功能了。例如,vuex-router-sync 库,通过在一个动态注册的模块中管理应用的路由状态,从而将 vue-router 和 vuex 集成。

你也能用 store.unregisterModule(moduleName) 移除动态注册过的模块。但是你不能用这个方法移除静态的模块(也就是在 store 创建的时候声明的模块)。

Plugins

Vuex 的 store 接收 plugins 选项,这个选项暴露出每个 mutation 的钩子。一个 Vuex 的插件就是一个简单的方法,接收 sotre 作为唯一参数:

const myPlugin = store => {
 // 当 store 在被初始化完成时被调用
 store.subscribe((mutation, state) => {
 // mutation 之后被调用
 // mutation 的格式为 {type, payload}。
 })
}

然后像这样使用:

const store = new Vuex.Store({
 // ...
 plugins: [myPlugin]
})

在插件内提交 Mutations

插件不能直接修改状态 - 这就像你的组件,它们只能被 mutations 来触发改变。

通过提交 mutations,插件可以用来同步数据源到 store。例如, 为了同步 websocket 数据源到 store (这只是为说明用法的例子,在实际中,createPlugin 方法会附加更多的可选项,来完成复杂的任务)。

export default function createWebSocketPlugin (socket) {
 return store => {
 socket.on('data', data => {
  store.commit('receiveData', data)
 })
 store.subscribe(mutation => {
  if (mutation.type === 'UPDATE_DATA') {
  socket.emit('update', mutation.payload)
  }
 })
 }
}
const plugin = createWebSocketPlugin(socket)

const store = new Vuex.Store({
 state,
 mutations,
 plugins: [plugin]
})

生成状态快照

有时候插件想获取状态 “快照” 和状态的改变前后的变化。为了实现这些功能,需要对状态对象进行深拷贝:

const myPluginWithSnapshot = store => {
 let prevState = _.cloneDeep(store.state)
 store.subscribe((mutation, state) => {
 let nextState = _.cloneDeep(state)

 // 对比 prevState 和 nextState...

 // 保存状态,用于下一次 mutation
 prevState = nextState
 })
}

** 生成状态快照的插件只能在开发阶段使用,使用 Webpack 或 Browserify,让构建工具帮我们处理:

const store = new Vuex.Store({
 // ...
 plugins: process.env.NODE_ENV !== 'production'
 ? [myPluginWithSnapshot]
 : []
})

插件默认会被起用。为了发布产品,你需要用 Webpack 的 DefinePlugin 或者 Browserify 的 envify 来转换 process.env.NODE_ENV !== 'production' 的值为 false。

内置 Logger 插件

如果你正在使用 vue-devtools,你可能不需要。

Vuex 带来一个日志插件用于一般的调试:

import createLogger from 'vuex/dist/logger'

const store = new Vuex.Store({
 plugins: [createLogger()]
})

createLogger 方法有几个配置项:

const logger = createLogger({
 collapsed: false, // 自动展开记录 mutation
 transformer (state) {
 // 在记录之前前进行转换
 // 例如,只返回指定的子树
 return state.subTree
 },
 mutationTransformer (mutation) {
 // mutation 格式 { type, payload }
 // 我们可以按照想要的方式进行格式化
 return mutation.type
 }
})

日志插件还可以直接通过 <script> 标签, 然后它会提供全局方法 createVuexLogger 。

要注意,logger 插件会生成状态快照,所以仅在开发环境使用。

严格模式

要启用严格模式,只需在创建 Vuex store 的时候简单地传入 strict: true。

const store = new Vuex.Store({
 // ...
 strict: true
})

在严格模式下,只要 Vuex 状态在 mutation 方法外被修改就会抛出错误。这确保了所有状态修改都会明确的被调试工具跟踪。

开发阶段 vs. 发布阶段

不要在发布阶段开启严格模式! 严格模式会对状态树进行深度监测来检测不合适的修改 —— 确保在发布阶段关闭它避免性能损耗。
跟处理插件的情况类似,我们可以让构建工具来处理:

const store = new Vuex.Store({
 // ...
 strict: process.env.NODE_ENV !== 'production'
})

相关引用

http://vuex.vuejs.org/en/plugins.html
http://vuex.vuejs.org/en/strict.html
http://vuex.vuejs.org/en/modules.html
http://vuex.vuejs.org/en/structure.html

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

Javascript 相关文章推荐
细说javascript函数从函数的构成开始
Aug 29 Javascript
javascript模拟枚举的简单实例
Mar 06 Javascript
javascript中select下拉框的用法总结
Jan 07 Javascript
微信小程序 MINA文件结构
Oct 17 Javascript
AngularJS  双向数据绑定详解简单实例
Oct 20 Javascript
js闭包用法实例详解
Dec 13 Javascript
bootstrap table实现x-editable的行单元格编辑及解决数据Empty和支持多样式问题
Aug 10 Javascript
在 Angular6 中使用 HTTP 请求服务端数据的步骤详解
Aug 06 Javascript
vue 移动端注入骨架屏的配置方法
Jun 25 Javascript
vue 使用 vue-pdf 实现pdf在线预览的示例代码
Apr 26 Javascript
node运行js获得输出的三种方式示例详解
Jul 02 Javascript
JavaScript 闭包的使用场景
Sep 17 Javascript
Vuex2.0+Vue2.0构建备忘录应用实践
Nov 30 #Javascript
BootStrap实现响应式布局导航栏折叠隐藏效果(在小屏幕、手机屏幕浏览时自动折叠隐藏)
Nov 30 #Javascript
JavaScript实现拖拽元素对齐到网格(每次移动固定距离)
Nov 30 #Javascript
jquery.Callbacks的实现详解
Nov 30 #Javascript
javascript中活灵活现的Array对象详解
Nov 30 #Javascript
如何处理JSON中的特殊字符
Nov 30 #Javascript
Angular.JS判断复选框checkbox是否选中并实时显示
Nov 30 #Javascript
You might like
PHP JSON格式数据交互实例代码详解
2011/01/13 PHP
Codeigniter校验ip地址的方法
2015/03/21 PHP
php超快高效率统计大文件行数
2015/07/05 PHP
微信 getAccessToken方法详解及实例
2016/11/23 PHP
PHP区块查询实现方法分析
2018/05/12 PHP
js实现input框文字动态变换显示效果
2015/08/19 Javascript
javascript拖拽应用实例(二)
2016/03/25 Javascript
JavaScript中的this使用详解
2016/07/27 Javascript
JavaScript重定向URL参数的两种方法小结
2016/10/19 Javascript
Vue.js开发环境搭建
2016/11/10 Javascript
如何防止INPUT按回车自动提交表单FORM
2016/12/06 Javascript
Node.js 中exports 和 module.exports 的区别
2017/03/14 Javascript
JS中实现隐藏部分姓名或者电话号码的代码
2018/07/17 Javascript
微信小程序表单弹窗实例
2018/07/19 Javascript
Nodejs中获取当前函数被调用的行数及文件名详解
2018/12/12 NodeJs
[01:05:12]2014 DOTA2国际邀请赛中国区预选赛 TongFu VS CIS-GAME
2014/05/21 DOTA
[01:02]DOTA2上海特锦赛SHOWOPEN
2016/03/25 DOTA
[49:43]VG vs FNATIC 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/17 DOTA
Python中的True,False条件判断实例分析
2015/01/12 Python
python爬虫爬取淘宝商品信息(selenum+phontomjs)
2018/02/24 Python
python 搭建简单的http server,可直接post文件的实例
2019/01/03 Python
python利用Tesseract识别验证码的方法示例
2019/01/21 Python
python tkinter窗口最大化的实现
2019/07/15 Python
解决Python二维数组赋值问题
2019/11/28 Python
美国婚礼礼品网站:MyWeddingFavors
2018/09/26 全球购物
Chicco婴儿用品美国官网:汽车座椅、婴儿推车、高脚椅等
2018/11/05 全球购物
销售代表求职自荐信
2013/10/01 职场文书
珍惜时间演讲稿
2014/05/14 职场文书
环卫工人先进事迹材料
2014/06/02 职场文书
幼儿园法制宣传日活动总结
2014/11/01 职场文书
公司给客户的感谢信
2015/01/23 职场文书
学校通报表扬范文
2015/05/04 职场文书
党支部考察鉴定意见
2015/06/02 职场文书
经典爱情感言
2015/08/03 职场文书
用golang如何替换某个文件中的字符串
2021/04/25 Golang
python通过函数名调用函数的几种方法总结
2021/06/07 Python