概念
- vuex是一个专为vue.js应用程序开发的状态管理模式,它采用的集中式存储管理应用所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。vuex也集成到vue的官方调试工具。
- 状态管理模式、集中管式存储管理,其实可以理解成把多个组件需要共享的变量存储在一个对象里面;然后将这个对象放在顶层的vue组件示例中,让其他组件也可以使用。
- 自己也可以封装一个对象,但不能保证所有的属性都是响应式的
- 一般在大型项目开发中,比如用户的登录状态、用户名称、头像、地理位置等都是需要在组件之间共享的状态
单界面状态管理
<template>
<div id="app">
<div>Hello</div>
<div>{{count}}</div>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</div>
</template>
<script>
export default {
name: 'App',
data:function(){
return {
count:0
}
},
components: {
},
methods:{
increment(){
this.count++;
},
decrement(){
this.count--;
}
}
}
state:data中count
view:视图层,template中显示count
action:@click 事件
多界面状态管理
全局单例模式
- 将共享的状态抽取出来,交给我们的大管家统一管理
- 之后每个视图,按照规定,进行访问和修改等操作
Vue Components–>Action–>Mutation–>State–>Vue Components(正常操作,action可以有异步操作)
Vue Components—>Mutation (只能是同步操作)
Mutation<---->Devtools(插件)
基本使用
注意:
- Vuex不是constructor
- 创建对象时用的是Vuex.Store,这个也跟我们创建文件名store是一致的
//store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
// 1安装插件
Vue.use(Vuex)
//2创建对象
const store = new Vuex.Store({
state:{
count:0
},
mutations:{
//state默认参数,不需要我们自己传,和store对象中的state是一样的
increment(state){
state.count++;
},
decrement(state){
state.count--;
}
},
action:{},
getters:{
},
modules:{
}
})
//3导出对象
export default store
//app.vue
<template>
<div id="app">
<div>Hello</div>
<div>{{count}}</div>
<button @click="incrementAction">+</button>
<button @click="decrementAction">-</button>
</div>
</template>
<script>
export default {
name: 'App',
data:function(){
return {
}
},
//定义一个计算属性,属性的值经常变化
computed:{
count: function () {
return this.$store.state.count;
}
},
components: {
},
methods:{
incrementAction(){
this.$store.commit('increment')
},
decrementAction(){
this.$store.commit('decrement')
}
}
}
</script>
总结:
-
提取出一个公共的store对象,用于保存在多个组件中共享的状态
-
将store对象放置在new vue对象中,这样可以保证在所有的组件中都可以使用
-
在其他组件中使用store对象中保存的状态即可
通过this.$store.state.属性的方式来访问状态;通过this.$store.commit(‘mutation中方法’)来修改状态;
-
我们是通过mutation的方式,而非直接改变store.state.count,这是因为Vuex可以更明确的追踪状态的变化,所以不要直接改变store.state.count的值
Getters的使用
单一状态树(Single Source of Truth)
如果你的状态信息保存到多个store对象中,那么之后的管理和维护等等都会变的特别困难,随意vuex使用了单一状态树来管理应用层的全部状态,单一状态树能够让我们最直接的方式找到某个状态的片段,而且之后的维护和调试过程中,也可以非常方便的管理和维护
Getter类似Computed中的属性
//store/index.js
const store = new Vuex.Store({
state:{
count:0,
students:[
{id:1,name:'kobe',age:12},
{id:2,name:'james',age:14},
{id:3,name:'kuli',age:10},
]
},
getters:{
greaterAgeCount:state=>{
return state.students.filter(item=>item.age>11);
}
},
})
<template>
<div id="app">
<div>{{greater11}}</div>
</div>
</template>
<script>
export default {
name: 'App',
computed:{
greater11:function(){
return this.$store.getters.greaterAgeCount;
}
},
}
</script>
Getters传参数
注意:getters默认是不能传递参数的,如果希望传递参数,那么只能让getters本身返回另一个函数
//vue/index.js
const store = new Vuex.Store({
state:{
count:0,
students:[
{id:1,name:'kobe',age:12},
{id:2,name:'james',age:14},
{id:3,name:'kuli',age:10},
]
},
getters:{
greaterAge:state=>{
//返回一个函数,可接受参数age
return (age)=>{
return state.students.filter(item=>item.age>age)
}
},
},
})
// App.vue
<template>
<div id="app">
<div>Hello</div>
<div>{{count}}</div>
<button @click="incrementAction">+</button>
<button @click="decrementAction">-</button>
<div>{{greater11}}</div>
<div>{{greaterAge}}</div>
</div>
</template>
<script>
export default {
name: 'App',
computed:{
greaterAge:function(){
return this.$store.getters.greaterAge(12);
}
},
}
</script>
Mutations状态更新
vuex中的state状态更新的唯一方式:提交Mutaiton
Mutation主要包括两部分:
- 字符串的事件类型,如果increment
- 一个回调函数(handler),该回调函数的第一参数就是state,如increment后面的函数
定义方式:
mutations:{
//state默认参数,不需要我们自己传,和store对象中的state是一样的
increment(state){
state.count++;
},
decrement(state){
state.count--;
}
},
更新方式:
methods:{
incrementAction(){
this.$store.commit('increment')
},
decrementAction(){
this.$store.commit('decrement')
}
}
Mutations传递参数
在通过mutation更新数据的时候,有可能我们携带一些额外的参数
- 参数被成为是mutation的载荷(Payload)
- 如果参数不是不止一个,通常我们会以对象的形式传递
//定义
mutations:{
incrementCount(state, count) {
state.count = state.count + count;
}
},
//调用
methods:{
incrementCountAction(){
this.$store.commit('incrementCount',5)
}
}
Mutations响应规则
Vuex中的store是响应式的,当state中的数据发生改变,vue组件会自动更新
规则:
- 提前在store中初始化所需要的属性
- 当给state中的对象添加属性时,使用下面的方式:
方式一:使用vue.set(obj,‘newProp’,123)
方式二:用新对象给老对象赋值
初始化所有属性响应式
mutations:{
addstudent(state){
state.students.push({
id:4,
name:'test',
age:13,
});
}
},
添加属性非响应式
const store = new Vuex.Store({
state:{
info:{
name:'ly',
age:18
}
},
mutations:{
updateInfo(state){
state.info['address']='jx'
}
},
})
methods:{
updateInfo(){
this.$store.commit('updateInfo');
}
}
添加属性响应式
- 方式一:Vue.set
updateInfo(state){
Vue.set(state.info,'address','jx')
}
- 方式二:用新对象给老对象赋值
updateInfo(state){
state.info={...state.info,'address':'jx'}
}
删除属性非响应式
updateInfo(state){
delete state.info.age
}
删除属性相应式
updateInfo(state){
Vue.delete(state.info,'age')
}
mutations const
定义
store/mutationtype.js
export const INCREMENT ='increment';
使用
//store/index.js
mutations:{
//state默认参数,不需要我们自己传,和store对象中的state是一样的
[INCREMENT](state){
state.count++;
},
}
//app.vue
methods:{
incrementAction(){
this.$store.commit(INCREMENT)
},
}
Mutations同步函数
通常情况下,vuex要求我们Mutation中的方法必须是同步方法
- 主要是因为当我们使用devtool时,devtool可以帮助我们捕捉mutation的快照
- 但是如果是异步操作,devtools将不能很好的追踪这个操作什么时候会被完成
- 当执行异步操作时,你会发现界面上的数据更新了,但是devtool中的state的数据没有更新
Actions
Actions类似于Mutations,用来替代Mutation进行异步操作
可以返回promise中
Actions的基本使用
定义
store/index.js
actions: {
aUpdatename(context) {
setTimeout(() => {
//context.state.info.name="ssh";不要这样修改
context.commit('updatename');
}, 1000);
}
},
App.vue
调用
updatename() {
this.$store.dispatch('aUpdatename');
}
store/index.js
传参
mutations:{
updatename(state, pageload){
setTimeout(()=>{
state.info.name = pageload;
},1000)
}
},
actions: {
aUpdatename(context,payload) {
setTimeout(() => {
//context.state.info.name="ssh";不要这样修改
context.commit('updatename',payload);
console.log(payload);
}, 1000);
}
},
App.vue
methods:{
updatename() {
//this.$store.commit('updatename');
this.$store.dispatch('aUpdatename','我是pageload');
}
}
执行成功,回调
方式一:(不建议)
App.vue
updatename() {
this.$store.dispatch('aUpdatename', ()=>{
console.log("执行成功");
});
}
index.js
actions: {
aUpdatename(context, payload) {
setTimeout(() => {
context.commit('updatename',payload);
console.log(payload);
payload();
}, 1000);
}
},
方式二 promise
aUpdatename(context, payload) {
return new Promise((resolve,reject)=>{
setTimeout(() => {
context.commit('updatename',payload);
console.log(payload);
resolve('success');
}, 1000);
})
}
updatename() {
this.$store.dispatch('aUpdatename', 'pageload').then(res=>{
console.log(res);
});
}
mudules
vue使用单一状态树,那么也意味着很多状态都会交给vuex来管理
当应用变得非常复杂时,store对象就有可能变得相当臃肿,为了解决这个问题,vuex允许我们将store分割成块(module),而每个模块拥有自己得state,mutations,actions,getters等
state得使用
<div>{{$store.state.a.name}}</div>
modules:{
a:{
state:{
name:'modelue A'
},
}
}
mutations的使用
mutations:{
updatename(state) {
state.info.name = 'ss';
}
},
modules:{
a:{
state:{
name:'modelue A'
},
mutations:{
updatename(state){
state.name="module aleter name"
}
}
}
}
当在App.vue中调用时
updatename(){
this.$store.commit("updatename");
}
优先在mutations中找,然后再从modules中得mutations中找
getters的使用
定义
modules:{
a:{
getters:{
fullname(state){
return state.name + "11111";
},
fullname2({state,getters,rootState}) {
return gutters.fullname + 2222;
}
}
}
}
app.vue
<div>{{$store.getters.fullname}}</div>
<div>{{$store.getters.fullname2}}</div>
如果根store中与module中的store有相同的getter是,会报错误
actions的用法
modules:{
a:{
mutations:{
updatename(state){
state.name="module aleter name"
}
},
actions:{
aUpdatename({state,commit,rootState}){
setTimeout(()=>{
context.commit('updatename');
},1000)
}
}
}
}
methods:{
aUpdateName(){
this.$store.dispatch("aUpdatename");
}
}
store 项目结构的优化
import Vue from 'vue'
import Vuex from 'vuex'
import Mutations from './mutations'
import Acions from './actions'
import Getters from './getters'
import ModuleA from './modules/moduleA'
// 1安装插件
Vue.use(Vuex)
const obj = {
name:'lls',
age:18,
height:170
}
const {name ,age, height}= obj
console.log(name)
//2创建对象
const store = new Vuex.Store({
state: {
count: 0,
students: [
{ id: 1, name: 'kobe', age: 12 },
{ id: 2, name: 'james', age: 14 },
{ id: 3, name: 'kuli', age: 10 },
],
info: {
name: 'ly',
age: 18
}
},
mutations: Mutations,
actions: Acions,
getters: Getters,
modules: {
a: ModuleA
}
})
//3导出对象
export default store
mutations,actions,getters,modules都抽到对应的文件里去,这样好维护,代码看起来也简洁