Skip to content

Commit 730b369

Browse files
riophaeyyx990803
authored andcommitted
updated the Chinese translation of modules.md (#796)
1 parent 44d4a72 commit 730b369

File tree

1 file changed

+153
-35
lines changed

1 file changed

+153
-35
lines changed

docs/zh-cn/modules.md

Lines changed: 153 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
# Modules
2+
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
23

3-
使用单一状态树,导致应用的所有状态集中到一个很大的对象。但是,当应用变得很大时,store 对象会变得臃肿不堪。
4-
5-
为了解决以上问题,Vuex 允许我们将 store 分割到**模块(module)**。每个模块拥有自己的 state、mutation、action、getters、甚至是嵌套子模块——从上至下进行类似的分割:
4+
为了解决以上问题,Vuex 允许我们将 store 分割成**模块(module)**。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:
65

76
``` js
87
const moduleA = {
@@ -31,14 +30,14 @@ store.state.b // -> moduleB 的状态
3130

3231
### 模块的局部状态
3332

34-
对于模块内部的 mutation 和 getter,接收的第一个参数是**模块的局部状态**
33+
对于模块内部的 mutation 和 getter,接收的第一个参数是**模块的局部状态对象**
3534

3635
``` js
3736
const moduleA = {
3837
state: { count: 0 },
3938
mutations: {
4039
increment (state) {
41-
// state 模块的局部状态
40+
// 这里的 `state` 对象是模块的局部状态
4241
state.count++
4342
}
4443
},
@@ -51,7 +50,7 @@ const moduleA = {
5150
}
5251
```
5352

54-
同样,对于模块内部的 action,`context.state` 是局部状态,根节点的状态是 `context.rootState`:
53+
同样,对于模块内部的 action,局部状态通过 `context.state` 暴露出来, 根节点状态则为 `context.rootState`
5554

5655
``` js
5756
const moduleA = {
@@ -66,7 +65,7 @@ const moduleA = {
6665
}
6766
```
6867

69-
对于模块内部的 getter,根节点状态会作为第三个参数
68+
对于模块内部的 getter,根节点状态会作为第三个参数暴露出来
7069

7170
``` js
7271
const moduleA = {
@@ -81,41 +80,133 @@ const moduleA = {
8180

8281
### 命名空间
8382

84-
模块内部的 action、mutation和 getter 现在仍然注册在**全局命名空间**——这样保证了多个模块能够响应同一 mutation 或 action。你可以通过添加前缀或后缀的方式隔离各模块,以避免名称冲突。你也可能希望写出一个可复用的模块,其使用环境不可控。例如,我们想创建一个 `todos` 模块
83+
默认情况下,模块内部的 action、mutation 和 getter 是注册在**全局命名空间**的——这样使得多个模块能够对同一 mutation 或 action 作出响应。如果希望你的模块更加自包含或提高可重用性,你可以通过添加 `namespaced: true` 的方式使其成为命名空间模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。例如
8584

8685
``` js
87-
// types.js
86+
const store = new Vuex.Store({
87+
modules: {
88+
account: {
89+
namespaced: true,
90+
// 模块内容(module assets)
91+
state: { ... }, // 模块内的状态已经是嵌套的了,使用 `namespaced` 属性不会对其产生影响
92+
getters: {
93+
isAdmin () { ... } // -> getters['account/isAdmin']
94+
},
95+
actions: {
96+
login () { ... } // -> dispatch('account/login')
97+
},
98+
mutations: {
99+
login () { ... } // -> commit('account/login')
100+
},
101+
// 嵌套模块
102+
modules: {
103+
// 继承父模块的命名空间
104+
myPage: {
105+
state: { ... },
106+
getters: {
107+
profile () { ... } // -> getters['account/profile']
108+
}
109+
},
110+
// 进一步嵌套命名空间
111+
posts: {
112+
namespaced: true,
113+
state: { ... },
114+
getters: {
115+
popular () { ... } // -> getters['account/posts/popular']
116+
}
117+
}
118+
}
119+
}
120+
}
121+
})
122+
```
123+
124+
启用了命名空间的 getter 和 action 会收到局部化的 `getter``dispatch``commit`。换言之,你在使用模块内容(module assets)时不需要在同一模块内额外添加空间名前缀。更改 `namespaced` 属性后不需要修改模块内的代码。
125+
126+
#### 在命名空间模块内访问全局内容(Global Assets)
127+
128+
如果你希望使用全局 state 和 getter,`rootState``rootGetter` 会作为第三和第四参数传入 getter,也会通过 `context` 对象的属性传入 action。
129+
130+
若需要在全局命名空间内分发 action 或提交 mutation,将 `{ root: true }` 作为第三参数传给 `dispatch``commit` 即可。
88131

89-
// 定义 getter、action、和 mutation 的名称为常量,以模块名 `todos` 为前缀
90-
export const DONE_COUNT = 'todos/DONE_COUNT'
91-
export const FETCH_ALL = 'todos/FETCH_ALL'
92-
export const TOGGLE_DONE = 'todos/TOGGLE_DONE'
132+
``` js
133+
modules: {
134+
foo: {
135+
namespaced: true,
136+
getters: {
137+
// 在这个模块的 getter 中,`getters` 被局部化了
138+
// 你可以使用 getter 的第四个参数来调用 `rootGetters`
139+
someGetter (state, getters, rootState, rootGetters) {
140+
getters.someOtherGetter // -> 'foo/someOtherGetter'
141+
rootGetters.someOtherGetter // -> 'someOtherGetter'
142+
},
143+
someOtherGetter: state => { ... }
144+
},
145+
actions: {
146+
// 在这个模块中, dispatch 和 commit 也被局部化了
147+
// 他们可以接受 `root` 属性以访问根 dispatch 或 commit
148+
someAction ({ dispatch, commit, getters, rootGetters }) {
149+
getters.someGetter // -> 'foo/someGetter'
150+
rootGetters.someGetter // -> 'someGetter'
151+
dispatch('someOtherAction') // -> 'foo/someOtherAction'
152+
dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'
153+
commit('someMutation') // -> 'foo/someMutation'
154+
commit('someMutation', null, { root: true }) // -> 'someMutation'
155+
},
156+
someOtherAction (ctx, payload) { ... }
157+
}
158+
}
159+
}
93160
```
94161

162+
#### 带命名空间的绑定函数
163+
164+
当使用 `mapState`, `mapGetters`, `mapActions``mapMutations` 这些函数来绑定命名空间模块时,写起来可能比较繁琐:
165+
95166
``` js
96-
// modules/todos.js
97-
import * as types from '../types'
167+
computed: {
168+
...mapState({
169+
a: state => state.some.nested.module.a,
170+
b: state => state.some.nested.module.b
171+
})
172+
},
173+
methods: {
174+
...mapActions([
175+
'some/nested/module/foo',
176+
'some/nested/module/bar'
177+
])
178+
}
179+
```
98180

99-
// 使用添加了前缀的名称定义 getter、action 和 mutation
100-
const todosModule = {
101-
state: { todos: [] },
181+
对于这种情况,你可以将模块的空间名称字符串作为第一个参数传递给上述函数,这样所有绑定都会自动将该模块作为上下文。于是上面的例子可以简化为:
102182

103-
getters: {
104-
[types.DONE_COUNT] (state) {
105-
// ...
106-
}
107-
},
183+
``` js
184+
computed: {
185+
...mapState('some/nested/module', {
186+
a: state => state.a,
187+
b: state => state.b
188+
})
189+
},
190+
methods: {
191+
...mapActions('some/nested/module', [
192+
'foo',
193+
'bar'
194+
])
195+
}
196+
```
108197

109-
actions: {
110-
[types.FETCH_ALL] (context, payload) {
111-
// ...
112-
}
113-
},
198+
#### 给插件开发者的注意事项
114199

115-
mutations: {
116-
[types.TOGGLE_DONE] (state, payload) {
117-
// ...
118-
}
200+
如果你开发的[插件(Plugin)](plugins.md)提供了模块并允许用户将其添加到 Vuex store,可能需要考虑模块的空间名称问题。对于这种情况,你可以通过插件的参数对象来允许用户指定空间名称:
201+
202+
``` js
203+
// 通过插件的参数对象得到空间名称
204+
// 然后返回 Vuex 插件函数
205+
export function createPlugin (options = {}) {
206+
return function (store) {
207+
// 把空间名字添加到插件模块的类型(type)中去
208+
const namespace = options.namespace || ''
209+
store.dispatch(namespace + 'pluginAction')
119210
}
120211
}
121212
```
@@ -125,13 +216,40 @@ const todosModule = {
125216
在 store 创建**之后**,你可以使用 `store.registerModule` 方法注册模块:
126217

127218
``` js
219+
// 注册模块 `myModule`
128220
store.registerModule('myModule', {
129221
// ...
130222
})
223+
// 注册嵌套模块 `nested/myModule`
224+
store.registerModule(['nested', 'myModule'], {
225+
// ...
226+
})
131227
```
132228

133-
模块的状态将是 `store.state.myModule`
229+
之后就可以通过 `store.state.myModule``store.state.nested.myModule` 访问模块的状态
134230

135-
模块动态注册功能可以让其他 Vue 插件为了应用的 store 附加新模块,以此来分割 Vuex 的状态管理。例如,[`vuex-router-sync`](https://github.com/vuejs/vuex-router-sync) 插件可以集成 vue-router vuex,管理动态模块的路由状态
231+
模块动态注册功能使得其他 Vue 插件可以通过在 store 中附加新模块的方式来使用 Vuex 管理状态。例如,[`vuex-router-sync`](https://github.com/vuejs/vuex-router-sync) 插件就是通过动态注册模块将 vue-router vuex 结合在一起,实现应用的路由状态管理
136232

137-
你也可以使用 `store.unregisterModule(moduleName)` 动态地卸载模块。注意,你不能使用此方法卸载静态模块(在创建 store 时声明的模块)。
233+
你也可以使用 `store.unregisterModule(moduleName)` 来动态卸载模块。注意,你不能使用此方法卸载静态模块(即创建 store 时声明的模块)。
234+
235+
### 模块重用
236+
237+
有时我们可能需要创建一个模块的多个实例,例如:
238+
239+
- 创建多个 store,他们公用同一个模块
240+
- 在一个 store 中多次注册同一个模块
241+
242+
如果我们使用一个纯对象来声明模块的状态,那么这个状态对象会通过引用被共享,导致状态对象被修改时会 store 或模块间数据互相污染的问题。
243+
244+
实际上这和 Vue 组件内的 `data` 是同样的问题。因此解决办法也是相同的——使用一个函数来声明模块状态(仅 2.3.0+ 支持):
245+
246+
``` js
247+
const MyReusableModule = {
248+
state () {
249+
return {
250+
foo: 'bar'
251+
}
252+
},
253+
// mutation, action 和 getter 等等...
254+
}
255+
```

0 commit comments

Comments
 (0)