Vuex
一、什么是vuex?
Vuex是一个专门为Vue.js应用程序开发的状态管理模式,它采用集中式存储管理应用的所有组件的状态,并以响应的规则保证状态以一种可预测的方式发生变化。Vuex也集成到Vue的官方调试工具devtools extension,提供了诸如零配置的time-travel调试、状态快照导入导出等高级调试功能。
什么是“状态管理模式”?
这个状态自管理应用包含以下几个部分:
state,驱动应用的数据源;
view,以声明方式将state映射到视图;
actions,响应在view上的用户输入导致的状态变化
当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:
多个视图依赖于同一状态。
来自不同视图的行为需要变更同一状态。
对于问题一,传参的方法对于多层嵌套的组件将会非常频繁,并且对兄弟组件间的状态传递无能为了。
对于问题二,我们经常会采用父子组件直接引用或者通过时间来变更和同步状态的多份拷贝。
以上这些模式非常脆弱,通常会导致无法维护的代码。
因此,我们为什么不把组件的共享状态抽取出来,以一个全局单例模式管理呢?在这种模式下,我们的组件树构成了一个巨大的“视图”,不管树的哪个位置,任何组件都能获取状态或触发行为!
另外,通过定义和隔离状态管理中的各种概念并强制遵循一定的规则,我们的代码将会变得更结构化且易维护。
这就是Vuex背后的基本思想,借鉴了Flux、Redux和The Elm Architecture。与其他模式不同的是,Vuex是专门为Vue js 设计的状态管理库,以利用Vue js的细粒度数据响应机制来进行高效的状态更新。
什么情况下我应该使用Vuex?
虽然Vuex可以帮助我们管理共享状态,但也附带了更多的概念和框架。这需要对短期和长期效益进行权衡。
如果您不打算开发大型单页应用,使用Vuex可能是繁琐冗余的。确实是如此,如果您的应用够简单,您最好不要使用Vuex。一个简单的store模式就足够您所需了。但是,如果您构建一个中大型单页应用,您可能会考虑如何更好地在组件外部管理状态,Vuex将会成为自然而然的选择。引用Redux的作者Dan Abramov的话说就是:
Flux架构就像眼镜:您自会知道什么时候需要它。
二、使用步骤
安装
1.直接下载/ CDN引用
https://unpkq com/vuex
- NPM
npm install vuex --save-dev
在-个模块化的打包系统中,您必须显式地通过Vue.use()来安装Vuex:
在创建的store.js中引入并调用
import Vue from ‘vue’
import Vuex from ‘vuex’
Vue.use(Vuex)
Promise
Paga.Wuex依赖Promise。 如果你支持的浏览器并没有实现Promise (此如IE),那么你可以使用一个polyfill 例如 es6.promise
store(仓库)
每一个Vuex应用的核心就是store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态(state)。
Vuex和单纯的全局对象有以下两点不同:(store 仓库的特点)
1.Vuex的状态存储是响应式的。当Vue组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会相应地得到高效更新。
2.你不能直接改变store中的状态。改变store中的状态的唯一途径就是显式地提交(commit)mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用
实例:创建store
Vue.use(Vuex)
export default new Vuex.store({
state:{
count:0,
test:"你好啊"
}
})
核心概念
State(单一的状态树)
Getter
Mutation
Action
Module
State(单一的状态树)
Vuex使用单一状态树,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源(SSOT)”而存在。这也意味着,每个应用将仅仅包含一个store实例。单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。
单一状态树和模块化并不冲突,在后面的我们会讨论如何将状态和状态变更时间分布到各个子模块中。
在Vue组件中获得Vuex状态
由于Vuex的状态存储是响应式的,从store实例中读取状态最简单的方法就是在计算属性中返回某个状态。
模版中:
<h1>{{count}}</h1>
computed中:
count:function(){
return this.$store.state.count;
}
创建store.js文件
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state:{
count:0,
text:"你好"
}
})
main.js中:
import store from './store'
Vue.use(VueRouter)
new Vue({
store,
render:h => h(App),
}).$mount('#app')
每当store.state.count变化的时候,都会重新求取计算属性,并且处罚更新相关联的DOM。
然而,这种模式导致组件依赖全局状态单例。在模块化的构建系统中,在每个需要使用state的组件中需要频繁地导入,并且在测试组件时需要模拟状态。
Vuex通过store选项,提供了一种机制将状态从根组件注入到每一个子组件中。
Getter
有的组件中获取到store中的state,需要对进行加工才能使用,computed属性中就需要写操作函数,如果有多个组件中都需要进行这个操作,那么在各个组件中都写相同的函数,那就非常麻烦,这时就可以把这个相同的操作写到store中的getters,每个组件只要引用getter就可以了,非常方便。Getter就是把组件中共有的对state的操作进行了提取,它就是相当于对state的computed,所以它会获得state作为第一个参数。
调用方式:
Getter会暴露为store getters对象,你可以以属性的形式访问这些值:
实例:定义数据,给数组排序
store.js中
getters:{
storlist:function(state){
let newlist = state.list.sort(function(a,b){
return a-b
});
return newlist
}
}
app.js,模板中:
<h1 v-for="i in list" :key="i">{{i}}</h1>
app.js,computed中:
list:function(){
return this.$store.getters.storlist;
}
Mutation
更改Vuex的store中的状态的唯一方法是提交mutation。
Vue 中的mutation非常类似于事件:每个mutation都有一个字符串的事件类型(type)和一个回调函数(handler)。
这个回调函数就是我们实际进行状态更改的地方,并且它会接受state作为第一个参数:
你不能直接调用一个mutation handler。这个选项更像是事件注册:“当触发一个类型为increment的mutation时,调用此函数”,“要唤醒一个mutation handler,你需要相应的type调用store.commit方法:”
store.commit(increment)
实现功能:点击按钮,count+1
store.js中
mutations:{
increment:function(state){
state.count++;
}
}
app.vue,模板中
<button @click="inc>点击count+1</button>
app.vue,methods中
inc:function(){
this.$store.commit('increment')
}
提交负荷(payload)
你可以向store commit 传入额外的参数,即mutation的载荷(payload)
实例: 提交负荷,添加内容:
实现功能:点击按钮,将input中输入的内容添加到展示区
app.vue,模板中:
<input type="text" v-model.number="arrdata" />
<button @click="add">添加</button>
app.vue,data中:
arrdata:"",
app.vue,methods中:
add:function(){
this.$store.commit('addlist',this.arrdata)
}
Action
Action类似于mutation,不同在于:
Action提交的是mutation,而不是直接变更状态。
Action可以包含任意异步操作。
Action函数接受一个与store实例具有相同方法和属性的context对象,因此你可以调用context.commit提交一个 mutation,或者通过context.state和context.getters来获取
state和getters。
action:实现功能:点击按钮,添加信息:
store.js中:
actions:{
tea:function(context){
fetch("地址",{
"method":"post",
"headers":{'content-type':'application/x-www-form-urlencoded'},
"body":"username=zyp&userpwd=123456&userclass=64&type=4"
}
).then(function(res){
return res.json()
}).then(function(data){
context.commit('addtea',data)
})
}
}
app.vue,模板中:
<button @click="inc">显示信息</button>
<table>
<tr v-for="item in teacher" :key="item.id_coach">
<td>{{item.name_coach}}</td>
<td>{{item.type_coach}}</td>
</tr>
</table>
app.vue,methods中:
inc:function(){
this.$store.dispatch('tea')
},
app.vue,computed中:
teacher:function(){
return this.$store.state.teachers;
},
Module
由于使用单-状态树,应用的所有状态会集中到一个比较大的对象。当
应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将store分割成模块(module)每个模块拥有自己的state、mutation、 action、 getter. 甚至是嵌套子模块一从 上至下进行同样方式的分割: