关于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 相关文章推荐
asp 取文本框名称代码
Dec 02 Javascript
轻量级 JS ToolTip提示效果
Jul 20 Javascript
JavaScript控制Session操作方法
Jan 17 Javascript
jquery实现固定顶部导航效果(仿蘑菇街)
Mar 21 Javascript
JavaScript中Math.SQRT2属性的使用详解
Jun 14 Javascript
jQuery实现的跨容器无缝拖动效果代码
Jun 21 Javascript
Bootstrap 最常用的JS插件系列总结(图片轮播、标签切换等)
Jul 14 Javascript
Mongoose经常返回e11000 error的原因分析
Mar 29 Javascript
javascript简单写的判断电话号码实例
May 24 Javascript
详解利用Angular实现多团队模块化SPA开发框架
Nov 27 Javascript
Vue-CLI与Vuex使用方法实例分析
Jan 06 Javascript
electron踩坑之remote of undefined的解决
Oct 06 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制作新闻系统的思路
2006/10/09 PHP
PHP 定界符 使用技巧
2009/06/14 PHP
php metaphone()函数及php localeconv() 函数实例解析
2016/05/15 PHP
php 截取GBK文档某个位置开始的n个字符方法
2017/03/08 PHP
全面解析PHP面向对象的三大特征
2017/06/10 PHP
PHP进阶学习之Geo的地图定位算法详解
2019/06/19 PHP
根据鼠标的位置动态的控制层的位置
2009/11/24 Javascript
判断一个变量是数组Array类型的方法
2013/09/16 Javascript
JQuery打造省市下拉框联动效果
2014/05/18 Javascript
jQuery的one()方法用法实例
2015/01/19 Javascript
js实现的万能flv网页播放器代码
2016/04/30 Javascript
JavaScript函数节流概念与用法实例详解
2016/06/20 Javascript
jQuery获取file控件中图片的宽高与大小
2016/08/04 Javascript
jQuery序列化表单成对象的简单实现
2016/11/29 Javascript
原生js实现可拖拽效果
2017/02/28 Javascript
使用bootstraptable插件实现表格记录的查询、分页、排序操作
2017/08/06 Javascript
解决vue+element 键盘回车事件导致页面刷新的问题
2018/08/25 Javascript
vue-swiper的使用教程
2018/08/30 Javascript
vue实现重置表单信息为空的方法
2018/09/29 Javascript
js实现Element中input组件的部分功能并封装成组件(实例代码)
2021/03/02 Javascript
[01:11:02]Secret vs Newbee 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/17 DOTA
python list元素为tuple时的排序方法
2018/04/18 Python
Python实现的调用C语言函数功能简单实例
2019/03/13 Python
Python数据可视化实现多种图例代码详解
2020/07/14 Python
CSS Grid布局教程之什么是网格布局
2014/12/30 HTML / CSS
详解HTML5将footer置于页面最底部的方法(CSS+JS)
2018/10/11 HTML / CSS
澳大利亚领先的皮肤诊所:Skin Matrix(抗衰老、痤疮专家、药妆护肤)
2018/05/20 全球购物
模具专业推荐信
2013/10/30 职场文书
会计职业生涯规划范文
2014/01/04 职场文书
机关门卫的岗位职责
2014/04/29 职场文书
团结演讲稿范文
2014/05/23 职场文书
借条如何写
2015/05/26 职场文书
就业推荐表院系意见
2015/06/05 职场文书
Golang之sync.Pool使用详解
2021/05/06 Golang
面试必问:圣杯布局和双飞翼布局的区别
2021/05/13 HTML / CSS
防止web项目中的SQL注入
2021/12/06 MySQL