什么是vuex
Vuex是一个状态管理工具,采用集中式存储管理应用的所有组件的状态,并且以相应的规则保证状态可预测的方式发生改变。本质就是把组件的共享状态和触发修改状态的函数抽离出来,这样就能获得状态或者触发行为。
Vuex的特点
1.能够在vuex中集中管理共享的数据,易于开发和后期维护
2.能够高效地实现组件之间的数据共享, 提高开发效率
3.存储在 vuex中的数据都是响应式的,能够实时保持数据与页面的同步
4.一般情况下,只有组件之间共享的数据,才有必要存储到vuex中;
5.对于组件中的私有数据,依旧存储在组件自身的data中即可.
什么情形下适合使用Vuex?
如果不打算开发大型单页应用,使用Vuex就会变得很冗余,就会有“牛刀杀鸡”的感觉,因为它会附带很多概念。这种情况下使用store模式就足够了。
如果正在开发一个中大型的单页应用,Vuex是更好的选择。
引入Vuex
1.手动下载引入
安装:
npm i vuex --save
导入:
import Vuex from "vuex"
Vue.use(Vuex)
创建仓库:
const store=new Vuex.Store({
state:{msg:"我就是所有共享的数据"}
})
把仓库挂载到vm对象:
new Vue({
render(h){return h(app)},
router,
store//挂载以后 所有的组件就可以直接从store中获取全局数据
}).$mount( "#app")
2.使用Vue脚手架安装
vue create app
选择配置vuex
再main.js文件夹下引入store
import store from './store'
挂载到vm对象,跟上面一样
State
创建state状态,状态就是那个存数据的对象
const store=new Vuex.store({
state:{data:"所有共享的数据"}
})
2.组件中访问数据
this.$store.state.msg
Getter
getter就像是store的计算属性,它会传入state对象供我们操作
设计
getters: {
//当作计数属性使用
mycomput(state){
//计算总价
return state.arr.reduce((n1,n2)=>{return n1+n2.price*n2.count},0)
}
},
使用
this.$store.getters.mycomput
Mutation
组件中希望更改 Vuex 的 store 中的状态(数据)的唯一方法是提交 mutation
不要用赋值表达式直接在组件中给store设置新数据
这样设计的原因是,只有通过mutation来更新数据,它才会去帮我们通知所有使用数据的组件更新数据 刷新UI
注意:一条重要的原则就是要记住 mutation 必须是同步处理
为什么必须是同步处理?
因为每一条mutation都会被devtools记录,devtools需要捕捉前一状态、后一状态。如果mutation函数中如果有异步函数,devtools无法得知异步函数什么时候执行,也就无法记录状态的变更。
设计:
mutations: {
mychange(state,obj){
方式一:state.arr[0].price=obj
方式二:state.arr[0].price=obj.n
}
},
使用:
//直接触发并传值(提交载荷)
方式一:this.$store.commit("mychange",10)
//可以以一个对象的形式传入
方式二:this.$store.commit("mychange",{n:10})
方式二另一种写法:this.$store.commit({type:"mychange",n:10}) //type属性值是需要触发的事件名,n则为obj下面的键值对
案例:
//vuex文件中
export default new Vuex.Store({
state: {
msg:"所有组件共享的数据",
arr:[{id:1,price:1,count:22},{id:2,price:2,count:25},{id:3,price:1,count:26}]
},
getters: {
//当作计数属性使用
mycomput(state){
//计算总价
return state.arr.reduce((n1,n2)=>{return n1+n2.price*n2.count},0)
}
},
//更改状态
mutations: {
mychange(state,obj){
state.arr[0].price=obj
}
},
})
//home组件中
<template>
<div>
<h2>home界面----{{$store.state.msg}}---总价:{{$store.getters.mycomput}}</h2>
<Box1></Box1>
<Box3></Box3>
</div>
</template>
<script>
export default {
components:{
Box1:()=>import("./views/Box1.vue"),
Box3: () => import("./views/Box3.vue")
}
}
</script>
//Box1组件中
<template>
<div id="">
<h2>Box1界面----{{this.$store.state.msg}}</h2>
<button @click="fn">点击修改第一个price</button>
</div>
</template>
<script>
export default {
methods: {
fn(){
this.$store.commit("mychange",10)
}
},
}
</script>
//Box3组件中
<template>
<div id="">
<h2>Box3界面----{{this.$store.state.msg}}</h2>
</div>
</template>
Action
actions选项的功能和mutations选项类似,但是也有不同之处:
Actions提交的是mutation,而不是直接变更状态;
Actions里面可以包含任意的异步操作;
所有的Action函数都接受一个与store实例具有相同方法和属性的context对象,这里的context对象指向当前的仓库,也就是store。因此在函数体中可以调用context.commit提交触发状态,相当于store.commit。这里注意,context对象不是store对象本身,这里相当于复制体。
设计:
actions: {
mychange2(ctx,obj){
setTimeout(()=>{
//提交载荷
ctx.commit("mychange",obj)
},1000)
}
},
使用:
//直接分发
this.$store.dispatch("mychange2", 20)
//以对象形式
this.$store.dispatch('mychange2',{n:20})
this.$store.dispatch({type: 'mychange2',n:20})
Module
可用于业务分块开发:
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter
//分块设计:
const moduleA = {
namespaced: true,//局部命名空间(让state的中变量与其他模块中的同名变量不冲突)
state: { msg:1 },
mutations: { change(state,n){state.msg=n} },
actions: { change(context,n){context.commit("change",n)} },
getters: { x(state){return state.msg} }
}
const moduleB = {
namespaced: true,//局部命名空间
state: { msg:1 },
mutations: { change(state,n){state.msg=n} },
actions: { change(context,n){context.commit("change",n)} },
getters: { x(state){return state.msg} }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
//组件中的使用:
this.$store.state.a.msg // -> moduleA 的状态
this.$store.state.b.msg // -> moduleB 的状态
this.$store.commit("a/change",100)-> moduleA 的mutations
this.$store.commit("b/change",200)-> moduleB 的mutations
this.$store.getters["a/x"]-> moduleA 的getters
this.$store.getters["b/x"]-> moduleB 的getters
this.$store.dispatch("a/change",100)-> moduleA 的actions
this.$store.dispatch("b/change",200)-> moduleB 的actions
总结
使用vuex步骤:
- 引入vuex;
- 全局注册Vuex,Vue.use(Vuex);
- 创建一个Vuex仓库,仓库里面可以包含五个选项:state(状态)、getters(对状态的过滤)、mutations(状态修改)、actions(异步提交修-改状态信息)、modules(模块);
- 触发mutation:通过commit触发仓库中的状态更新,store.commit(“对应的mutation”);
- 将仓库注入到Vue对象中,也可以挂载到Vue对象原型上;