目录
1.什么是Vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
2.Vuex的基本思想
把组件的共享状态抽取出来,以一个全局单例模式管理,在这种模式下,组件树构成了一个巨大的”视图“,不管在树的哪个位置,任何组件都能获取状态或者触发行为。
通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,代码将会变得更结构化且易维护。
3.安装
NPM:npm install vuex --save
Yarn:yarn add vuex
CDN:https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js
注意:在一个模块化的打包系统中,必须显式地通过 Vue.use() 来安装 Vuex(使用全局 script 标签引用 Vuex 时,则无需以下安装过程):
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
4.核心概念
Store:
存放Vue运行时各种状态的仓库/容器。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Vuex-Store</title>
</head>
<body>
<div id="app" v-once>
<!--不使用v-once的话,会无限执行test()-->
{{ test() }}
通过控制台查看或修改
</div>
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js"></script>
<script>
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++
}
}
})
new Vue({
el: '#app',
store: store,
// store //如果使用 ES6,可以简写为store (用在对象某个 property 的 key和被传入的变量同名时):
methods: {
test() {
this.$store.commit('increment')
console.log(this.$store.state.count)
}
},
})
</script>
</body>
</html>
State:
单一状态树。作为一个“唯一数据源“而存在,包含了全部的应用层级状态,这也意味着,每个应用仅包含一个 store 实例。
单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。
Vuex 通过 store 选项,提供了一种机制将状态从根组件“注入”到每一个子组件中,通过在根实例中注册 store 选项,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$store 访问到。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Vuex-Store</title>
</head>
<body>
<div id="app">
<counter></counter>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js"></script>
<script>
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++
}
}
})
const Counter = Vue.component('counter', {
template: `<div>{{ count }}</div>`,
computed: {
count() {
return this.$store.state.count
}
}
})
const app = new Vue({
el: '#app',
// 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
store: store,
components: {
Counter
},
template: `
<div class="app">
<counter></counter>
</div>
`
})
</script>
</body>
</html>
Getters:
可以认为是 store 的计算属性,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Vuex-Getters</title>
</head>
<body>
<div id="app">
控制台输入<q>store.getters.doneTodos</q>以属性访问
</br>
控制台输入<q>store.getters.getTodoById(2)</q>以方法访问
</div>
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js"></script>
<script>
const store = new Vuex.Store({
state: {
todos: [{
id: 1,
text: '这是第一条',
done: true
},
{
id: 2,
text: '这是第二条',
done: false
}
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
},
getTodoById: (state) => (id) => {
return state.todos.find(todo => todo.id === id)
}
}
})
</script>
</body>
</html>
Mutations:
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。通过这种方式虽然操作稍微繁琐一点,但是可以集中监控所有的数据的变化。
Mutations支持以载荷形式和以对象形式进行更改store中的状态。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Vuex-Mutations</title>
</head>
<body>
<div id="app">
控制台通过<q>store.commit('increment', {amount: 10})</q>以对象形式或者
</br>
<q>store.commit({type: 'increment',amount: 10})</q>以载荷形式更改store中的状态
</div>
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js"></script>
<script>
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state, payload) {
state.count += payload.amount
}
}
})
</script>
</body>
</html>
Actions:
Action 类似于 mutation,不同在于:①Action 提交的是 mutation,而不是直接变更状态。②Action 可以包含任意异步操作。
Actions 支持同样的载荷方式和对象方式进行分发。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Vuex-Actions</title>
</head>
<body>
<div id="app">
控制台通过<q>store.dispatch('increment')</q>触发
</div>
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js"></script>
<script>
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++
}
},
actions: {
incrementAsync({commit}) {
setTimeout(() => {
commit('increment')
}, 1000)
}
}
})
console.log(store.state.count);
store.dispatch('incrementAsync');
console.log(store.state.count);
</script>
</body>
</html>
Modules:
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。
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 的状态
store.state.b // -> moduleB 的状态