|
@@ -1,13 +1,13 @@
|
|
# 应用结构
|
|
# 应用结构
|
|
|
|
|
|
-Vuex 并非限制你的代码结构,而是遵循一些观点:
|
|
|
|
|
|
+Vuex 并不限制你的代码结构,但是制定了一套需要遵守的规则:
|
|
|
|
|
|
-1. 应用 state 存在于单个对象中
|
|
|
|
-2. 只有 mutation handlers 可以改变 state
|
|
|
|
-3. Mutations 必须是同步的,它们做的应该仅仅是改变 state
|
|
|
|
-4. 所有类似数据获取的异步操作细节都应在 actions 里
|
|
|
|
|
|
+1. 应用 state 存在于单个对象中;
|
|
|
|
+2. 只有 mutation handlers 可以改变 state;
|
|
|
|
+3. Mutations 必须是同步的,它们做的应该仅仅是改变 state;
|
|
|
|
+4. 所有类似数据获取的异步操作细节都应封装在 actions 里面。
|
|
|
|
|
|
-Vuex actions 和 mutations 很好的地方在于 **他们都仅仅是函数**。你只需要遵循以上的准则,怎么组织代码就取决于你自己了。最简单的 Vuex 实例甚至只需要在 [单个文件](https://github.com/vuejs/vuex/blob/master/examples/counter/vuex.js) 中声明!然而这对于很多项目来说并不够,所以这里有些根据不同应用规模推荐的不同结构。
|
|
|
|
|
|
+Vuex actions 和 mutations 优雅的地方在于 **它们都只是一些函数**。只需要遵循以上的准则,怎么组织代码就取决于你自己了。最简单的 Vuex store 实例甚至可以在 [单个文件](https://github.com/vuejs/vuex/blob/master/examples/counter/vuex.js) 中声明!然而这在真正的项目里显然是行不通的,所以这里有些根据不同应用规模推荐的不同结构。
|
|
|
|
|
|
### 简单的项目
|
|
### 简单的项目
|
|
|
|
|
|
@@ -20,19 +20,17 @@ Vuex actions 和 mutations 很好的地方在于 **他们都仅仅是函数**。
|
|
├── components
|
|
├── components
|
|
│ ├── App.vue
|
|
│ ├── App.vue
|
|
│ └── ...
|
|
│ └── ...
|
|
-└── vuex
|
|
|
|
|
|
+└── store
|
|
├── index.js # exports the vuex instance
|
|
├── index.js # exports the vuex instance
|
|
├── actions.js # exports all actions
|
|
├── actions.js # exports all actions
|
|
└── mutations.js # exports all mutations
|
|
└── mutations.js # exports all mutations
|
|
```
|
|
```
|
|
|
|
|
|
-一个真实的 [TodoMVC 例子](https://github.com/vuejs/vuex/tree/master/examples/todomvc).
|
|
|
|
|
|
+参见 [TodoMVC 示例](https://github.com/vuejs/vuex/tree/master/examples/todomvc).
|
|
|
|
|
|
-### Medium to Large Project
|
|
|
|
|
|
+### 中型到大型项目
|
|
|
|
|
|
-### 逐渐复杂的项目
|
|
|
|
-
|
|
|
|
-For any non-trivial app, we probably want to further split Vuex-related code into multiple "modules" (roughly comparable to "stores" in vanilla Flux), each dealing with a specific domain of our app. Each module would be managing a sub-tree of the state, exporting the initial state for that sub-tree and all mutations that operate on that sub-tree:
|
|
|
|
|
|
+对于有一定规模的项目,我们会希望把 Vuex 相关的代码分割到多个『模块 (module)』当中去,每一个 module 负责应用的一个领域(和原始 Flux 中的多个 store 类似)。在 Vuex 中,一个模块所要做的其实也就是导出 state 的一部分(可以理解为一颗子树),以及和该部分 state 相关的所有 mutations:
|
|
|
|
|
|
???
|
|
???
|
|
|
|
|
|
@@ -44,7 +42,7 @@ For any non-trivial app, we probably want to further split Vuex-related code int
|
|
├── components
|
|
├── components
|
|
│ ├── App.vue
|
|
│ ├── App.vue
|
|
│ └── ...
|
|
│ └── ...
|
|
-└── vuex
|
|
|
|
|
|
+└── store
|
|
├── actions.js # exports all actions
|
|
├── actions.js # exports all actions
|
|
├── index.js
|
|
├── index.js
|
|
├── modules
|
|
├── modules
|
|
@@ -56,13 +54,13 @@ For any non-trivial app, we probably want to further split Vuex-related code int
|
|
一个典型的模块:
|
|
一个典型的模块:
|
|
|
|
|
|
``` js
|
|
``` js
|
|
-// vuex/modules/products.js
|
|
|
|
|
|
+// store/modules/products.js
|
|
import { RECEIVE_PRODUCTS, ADD_TO_CART } from '../mutation-types'
|
|
import { RECEIVE_PRODUCTS, ADD_TO_CART } from '../mutation-types'
|
|
|
|
|
|
-// initial state
|
|
|
|
|
|
+// 该模块的初始状态
|
|
export const productsInitialState = []
|
|
export const productsInitialState = []
|
|
|
|
|
|
-// mutations
|
|
|
|
|
|
+// 相关的 mutations
|
|
export const productsMutations = {
|
|
export const productsMutations = {
|
|
[RECEIVE_PRODUCTS] (state, products) {
|
|
[RECEIVE_PRODUCTS] (state, products) {
|
|
state.products = products
|
|
state.products = products
|
|
@@ -77,49 +75,46 @@ export const productsMutations = {
|
|
}
|
|
}
|
|
```
|
|
```
|
|
|
|
|
|
-在 `vuex/index.js` 里我们把多个模块集合在一起来创建 Vuex 实例:
|
|
|
|
|
|
+在 `store/index.js` 里我们把多个模块集合在一起来创建 Vuex 实例:
|
|
|
|
|
|
``` js
|
|
``` js
|
|
import Vue from 'vue'
|
|
import Vue from 'vue'
|
|
import Vuex from '../../../src'
|
|
import Vuex from '../../../src'
|
|
import * as actions from './actions'
|
|
import * as actions from './actions'
|
|
-// import parts from modules
|
|
|
|
|
|
+// 导入各个模块的初始状态和 mutations
|
|
import { cartInitialState, cartMutations } from './modules/cart'
|
|
import { cartInitialState, cartMutations } from './modules/cart'
|
|
import { productsInitialState, productsMutations } from './modules/products'
|
|
import { productsInitialState, productsMutations } from './modules/products'
|
|
|
|
|
|
Vue.use(Vuex)
|
|
Vue.use(Vuex)
|
|
|
|
|
|
-export default new Vuex({
|
|
|
|
|
|
+export default new Vuex.Store({
|
|
// ...
|
|
// ...
|
|
- // combine sub-trees into root state
|
|
|
|
|
|
+ // 将各个模块的状态组合成最终的根状态 (root state)
|
|
state: {
|
|
state: {
|
|
cart: cartInitialState,
|
|
cart: cartInitialState,
|
|
products: productsInitialState
|
|
products: productsInitialState
|
|
},
|
|
},
|
|
- // mutations can be an array of mutation definition objects
|
|
|
|
- // from multiple modules
|
|
|
|
|
|
+ // mutations 选项可以是一个包含多个对象的数组
|
|
mutations: [cartMutations, productsMutations]
|
|
mutations: [cartMutations, productsMutations]
|
|
})
|
|
})
|
|
```
|
|
```
|
|
|
|
|
|
-Since all modules simply export objects and functions, they are quite easy to test and maintain. You are also free to alter the patterns used here to find a structure that fits your preference.
|
|
|
|
-
|
|
|
|
-Note that we do not put actions into modules, because a single action may dispatch mutations that affect multiple modules. It's also a good idea to decouple actions from the state shape and the implementation details of mutations for better separation of concerns. If the actions file gets too large, we can turn it into a folder and split out the implementations of long async actions into individual files.
|
|
|
|
|
|
+由于一个模块导出的仅仅是对象和函数,它们也是非常易于测试和维护的。当然,你也可以按你的喜好和需求对这样的组织方式进行修改。
|
|
|
|
|
|
-For an actual example, check out the [Shopping Cart Example](https://github.com/vuejs/vuex/tree/master/examples/shopping-cart).
|
|
|
|
|
|
+需要注意的一点:我们并不把 actions 放在模块里面,因为一个 action 可能需要触发影响多个模块的 mutations。同时,actions 本来就应该和具体的状态以及 mutations 解耦。如果单独的 actions 文件变得太过庞大,我们也可以划分出一个 actions 文件夹并将 actions 分散到多个文件中。
|
|
|
|
|
|
-???
|
|
|
|
|
|
+参见 [购物车示例](https://github.com/vuejs/vuex/tree/master/examples/shopping-cart)。
|
|
|
|
|
|
### 提取共用的 Computed Getters
|
|
### 提取共用的 Computed Getters
|
|
|
|
|
|
-在大型项目中,多个组件使用同一个基于 Vuex state 的 computed 属性是有可能的。由于 computed getters 只是普通函数,你可以把它们独立在另一个文件里,以实现共享:
|
|
|
|
|
|
+在大型项目中,你可能会发现有多个组件使用相似的计算属性来获取 state。由于计算属性的 getters 也只是普通函数,你可以把它们独立出来放在一个单独的文件里,以实现在多个组件之间的共享:
|
|
|
|
|
|
``` js
|
|
``` js
|
|
// getters.js
|
|
// getters.js
|
|
-import vuex from './vuex'
|
|
|
|
|
|
+import store from './store'
|
|
|
|
|
|
export function filteredTodos () {
|
|
export function filteredTodos () {
|
|
- return vuex.state.messages.filter(message => {
|
|
|
|
|
|
+ return store.state.messages.filter(message => {
|
|
return message.threadID === vuex.state.currentThreadID
|
|
return message.threadID === vuex.state.currentThreadID
|
|
})
|
|
})
|
|
}
|
|
}
|
|
@@ -136,4 +131,4 @@ export default {
|
|
}
|
|
}
|
|
```
|
|
```
|
|
|
|
|
|
-这非常像 [Getters in NuclearJS](https://optimizely.github.io/nuclear-js/docs/04-getters.html).
|
|
|
|
|
|
+这和 [NuclearJS 中的 Getters 概念](https://optimizely.github.io/nuclear-js/docs/04-getters.html) 非常相似。
|