Class20 - Vuex
作者:©Mrlin(史密斯林)
简介:学习记录,用于记录在CSDN课程中的学习内容。
课程:Vue2.x从入门到实战。Vue.js Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动.(来自官方介绍)
Vuex
用于多个组件共享状态全局管理。
在 vuex
中管理状态,就像是将状态统一存取。因而对于 vuex
来说,改变同步 state
的状态及其关键。因此,提供了一下属性:state
: 用于存储属性。getter
: vuex中的computed属性,用于简化模板标签中的表达式。mutation
: vuex中的同步操作action
: vuex中的异步操作module
: 用于大项目中的划分 vuex store
模块,方便多人分模块协同操作。
引入vuex
1
npm install --save vuex
创建 vuex
简单 对象1
2
3
4
5
6
7
8
9
10import Vue from 'vue'
import Vuex from "vuex";
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
count: 0
}
});
export default store;
在 主入口 js 中引入 store
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16import Vue from 'vue'
import App from './App'
import router from '../../router'
import store from '../../store'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
state
在 组件 中调用1
2
3
4
5computed:{
count(){
return this.$store.state.count
}
}
官方推荐,state中定义的属性放在computed
中,组件本身定义的属性放在data
中。这是因为data 中的内容只会在 created 钩子触发前初始化一次,这个时候如果data里面绑定的是vuex值类型数据,那么后面无论怎么修改vuex的state状态,data中对应的属性值是不会变化的,而 computed 则是通过依赖实现的,计算属性在它的相关依赖发生改变时会重新求值。
- 辅助函数
mapState
,用于简化vuex
中的属性映射。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23import { mapState } from 'vuex'
// 写法一
computed: mapState({
// 箭头函数可使代码更简练
count: state => state.count,
// 传字符串参数 'count' 等同于 `state => state.count`
countAlias: 'count',
// 为了能够使用 `this` 获取局部状态,必须使用常规函数
countPlusLocalState (state) {
return state.count + this.localCount
}
})
// 写法二
computed: {
newcount(){
return this.$store.state.count
},
...mapState({
count:'count'
})
}
getter
getter
的使用方法和state
相似。1
2
3
4
5computed: {
doneTodosCount() {
return this.$store.getters.doneTodosCount;
}
}
- 辅助函数
mapGetters
与mapState
使用方法一致1
2
3
4
5
6
7
8computed: {
...mapState({
count: "count"
}),
...mapGetters({
doneTodosCount: "doneTodosCount"
})
}
mutation
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。
mutation方法的参数: xxfunction(state,?,?,?)
定义一个mutation方法,如下:1
2
3
4
5mutations:{
increment (state, n) {
state.count += n
}
}
调用方式1
this.$store.commit('increment', 10);
(官网推荐)在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读:1
2
3
4
5mutations:{
increment (state, payload) {
state.count += payload.amount
}
}
Mutation 需遵守 Vue 的响应规则
既然 Vuex 的 store 中的状态是响应式的,那么当我们变更状态时,监视状态的 Vue 组件也会自动更新。这也意味着 Vuex 中的 mutation 也需要与使用 Vue 一样遵守一些注意事项:
最好提前在你的 store 中初始化好所有所需属性。
当需要在对象上添加新属性时,你应该
使用 Vue.set(obj, ‘newProp’, 123), 或者
以新对象替换老对象。例如,利用 stage-3 的对象展开运算符我们可以这样写:
1 | state.obj = { ...state.obj, newProp: 123 } |
示例:1
2
3
4
5
6state:{
user:{
userId: 0,
userName: 'admin'
}
}
当我们需要给他加入一个 count
属性时,定义 mutation
方法1
2
3
4
5updateUser (state, payload) {
// state.user.count = payload.amount //1
// state.user = { ...state.user, count: payload.amount } //2
// Vue.set(state.user, 'count', payload.amount) //3
}
上述的 2,3 方法便是官方推荐的正确的数据更新方法。
当我们使用方法 1 时,可以看出数据确实发生了变化,但是页面却没有渲染出来,这就是方法1的不便之处。
- 辅助函数
mapMutations
1
2
3
4
5
6
7
8
9
10
11
12import { mapMutations } from 'vuex'
methods: {
...mapMutations([
'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
// `mapMutations` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
]),
...mapMutations({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
})
}
action
Action
提交Mutation
,Mutation
变更状态Action
可以包含任意异步操作。
1 | mutations: { |
组件里调用1
this.$store.dispatch('updateCount')
- 辅助函数
mapActions
1
2
3
4
5
6
7
8
9
10
11methods: {
...mapActions([
'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
// `mapActions` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
]),
...mapActions({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
})
}
modules
modules
用于划分模块1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
使用 modules
时,需要使用命名空间1
namespaced:true
方法调用时,添加命名空间路径1
this.$store.commit("user/setUser", user);
大型项目,目录结构1
2
3
4
5
6
7
8
9
10
11
12
13
14├── index.html
├── main.js
├── api
│ └── ... # 抽取出API请求
├── components
│ ├── App.vue
│ └── ...
└── store
├── index.js # 我们组装模块并导出 store 的地方
├── actions.js # 根级别的 action
├── mutations.js # 根级别的 mutation
└── modules
├── cart.js # 购物车模块
└── products.js # 产品模块