Vuex基本概念——vue状态管理(一)

前言

随着WEB单页面(SPA)技术的兴起,越来越多的后端工作转移到了前端,不同组件之间数据共享成为亟需解决的问题。一个组件改变了数据值,其他使用到该数据的组件应该做出积极的响应与变化,这是同步问题就变得非常的麻烦。应用状态管理就是为完成数据同步问题的解决方案。管理应用程序的状态有多种不同的方法,在大中型单页面应用项目中,Vue引入了Vuex完成对多个组件之间需要共享数据或状态,完成集中式数据和状态管理, 使得一处修改,多处使用。

VUEX的安装

Vuex是一个专为Vue.js应用程序开发的状态管理插件,该插件并非是VUE管理应用程序的状态唯一的解决方案,使用前必须安装该插件。安装步骤如下

  1. 查看该组件是否已经安装。打开工程目录下的文件package.json,查看dependencies项,如下图所示,如果有"vuex"项,代表已经安装;如果没有安装需要通过npm进行安装。
    在这里插入图片描述
  2. 打开cmd窗口,进入项目所在目录,输入命令:cnpm install vuex –save或npm install vuex –save,完成vuex的安装
  3. 安装完成后,再次打开package.json文件,如上图所示如有"vuex"项代表已经成功安装

vuex五种基本对象

Vuex是一个专为Vue.js应用程序开发的状态管理模式。采用集中式存储管理应用所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。这些规则集中表现在Vuex五种默认的基本对象的使用上。

state对象:state为单一状态树,用来存储各种变量的值,变量可以是数组、对象、字符串等数据类型。只有在state中定义这些状态,在组件中才能获取、修改和读取的这个对象的状态。存储状态(变量或属性),它是一个简单的键值对对象。如

const state = {  
	  loginState: false  
	  ...  
	  } 

在这里定义一个state对象,state对象包含了一个属性(变量)loginState,它的数据类型是布尔型,默认值是false。
依赖这个数据的组件state值的获取通过this.$store.state.【key】,如loginState的获取为:

var loginState = this.$store.state.loginState

值得注意的是使用data接收state值,state中的状态改变的时候,需要将state值的获取放置到使用组件的computed中,才能监听到值的变化,数据和视图是同步的。

getters对象:从基本数据(state)派生的数据,相当于state的计算属性。在项目中使用Vuex的store实例时,如果需要对store的state对象状态值进行简单运算后再使用,这时就要用到store实例的计算属性getter。如:在state中记录营业额,营业额计量单位是元,统计模块要使用到营业额,但使用到计量单位是万元,此时就需要使用到getters,可以理解为state的计算属性。如:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    loginState: false,
    atm: 10020 //
  },
  getters: {     
    convertAtm: function(state) {
      return state.atm / 10000
    }
  }
})

export default store

在getters定义了一个营业额转换函数,在统计组件中可以直接使用,使用时再统计组件computed,通过 this.$store.getters.convertAtm获取所需的值。

Mutations对象:通过state对象或者Getters对象,组件可以非常方便的使用store实例中的状态。如果组件中需要更改store实例中的状态,则需要使用mutation提供的方法提交修改。以下通过一个示例说明Mutations对象的使用。
在state中有一个属性value记录当前值,在一个组件中获取到该值,在组件中包含两个按钮,分别用于增加或减少value值。store中代码如下

import Vuex from 'vuex'  
Vue.use(Vuex)  
const state = {    //定义state
  value: 1  
}   
const mutations = {  //定义mutations
  increment (state, v) {  
    state.value = parseInt(state.value) + parseInt(v)  
  },  
  decrement (state, v) {  
    state.value = parseInt(state.value) - parseInt(v)  
  }  
}  
export default new Vuex.Store({  
  state,  
  getters,  
  mutations  //注册mutations  
}) 

以上代码定义了一个state的值为1,在mutations中定义了increment和decrement两个方法,分别用于完成状态值的增加与减少。调用组件中代码如下:

import Vue from 'vue'  
<template>  
  <div class="hello">  
    <h1>使用computed接收:{{ computedmsg }}</h1> 
    <input type="number" value="1" v-model="num" />  
    <button @click="increment">+增加</button>  
    <button @click="decrement">-减少</button>  
  </div>  
</template>  
<script>  
export default {  
  name: 'hello',  
  data () {  
    return {  
      num: 1
    }  
  },  
  computed: {  
    computedmsg () {  
      return this.$store.state.value 
    }  
  },  
  methods: {  
    increment () {  
      this.$store.commit('increment', this.num)  //第一参数为store定义的函数名,第二个为参数
    },  
    decrement () {  
      this.$store.commit('decrement', this.num)  
    }  
  }  
}  
</script>  
<style>  
</style> 

当一个组件更改状态值时,通过this.$store.commit()方法进行修改,其中第一参数是mutations定义的函数名,第二个参数为要传入的参数。通过这种机制,将状态的变化规则封装到mutations对象中,而传入的参数为state变化的一个因素(参数)。
Actions对象:vuex是通过Mutations对象完成状态值的修改,一旦执行commit则state中的属性值就发生了变化,如果想在执行commit前或commit后完成一些操作是不可能。这时就必须借助Actions对象来完成。Actions类似于Mutations的代理对象,实际的状态修改提交工作是Mutations的commit完成,使用Actions可以动态的增强相应的功能。Actions对象使用时,在Actions中自定义的函数接收一个context参数和要变化的形参,context与store实例具有相同的方法和属性,所以它可以执行context.commit(’ ') 调用mutations里面的方法。示例代码如下:
【例】state中有一个count的属性,点击更改时,count的值更改为加上传入的参数,并且需要在更改此状态前,在控制台上输出“要不要更改状态?算了还是更改吧”。

import Vue from 'vue'  
import Vuex from 'vuex'  
  
//使用vuex模块  
Vue.use(Vuex);  
  
//声明静态常量为4  
const state = {  
  count: 4  
};  
const mutations = {  //这里使用已经能够完成state的增加了
  add(state, n) {  
    state.count += n.a;  
  }  
};  
//这里的actionAdd是组件中和所触发的事件相对应的方法  
const actions = {  
  increment(context,num) { //context官方给出的指定对象,可以理解为store对象,num代表参数  
    console.log(“要不要更改状态?算了还是更改吧”)
    context.commit('add', {//这里的add’是mutations中的方法  
      a: num.res //res为传递参数  
    })  
  },   
};  
  
//导出一个模块  
export default new Vuex.Store({  
  state,  
  mutations,  
  actions  
})  

这里increment为自定义函数,里面有context,num两个参数,/context官方给出的指定对象,可以理解为store对象,num代表参数,参数可以是单个值,也可以是对象、数组,这里的num是一个对象。
使用组件代码为:

<template>  
  <div class="hello">  
    <p>组件内部count{{count}}</p>  
    <button @click="addNum">+增加</button>  
  </div>  
</template>  
  
<script>  
  export default {  
    name: 'storeAction',  
    data() {  
      return {}  
    },  
    computed: {  
      count() {  
        return this.$store.state.count  
      }  
    },  
    methods: {  
      addNum() {  
        this.$store.dispatch('increment', {  
          res: 15  
        })  
      }
    }  
  }  
</script> 

在组件中可以通过this.$store.dispatch分发action,increment是action定义的参数名,{ res: 15 }是要传入的参数。

modules对象:Vuex使用单一状态树,所有状态会集中到一个对象中。当项目非常复杂时,store对象可能变得相当臃肿,不易维护。为了解决这个问题,Vuex允许将store分割成若干个模块(module)进行管理,每个模块拥有各自的 state、mutation、action、getter。
】创建modules模块,将系统store分割为app和user两个模块。
首先在项目store文件下创建modules文件夹用来存放系统状态分割的模块,并在此目录下创建app.js和user.js两个文件,用于项目级状态值的管理,app.js完整代码如下

const state = {  
  appName: '项目名称'  
}  
const getters = {  
  getName (state) {  
    return state.appName  
  }  
}  
const mutations = {  
  Set_Name (state, name) {  
    state.appName = name  
  }  
}  
const actions = {  
  setAppName (context, name) {  
    console.log(name)  
    context.commit('Set_Name', name)  
  }  
}  
export default {  
  namespaced: true, // 用于在全局引用方法时标识这一个的文件名  
  state,  
  getters,  
  mutations,  
  actions  
}  

user.js代码如下:

const state = {  
  userName: 'Felix'  
}  
const getters = {  
  getName (state) {  
    return state.userName  
  }  
}  
const mutations = {  
  Set_Name (state, name) {  
    state.userName = name  
  }  
}  
const actions = {  
  setUserName (context, name) {  
    context.commit('Set_Name', name)  
  }  
}  
export default {  
  namespaced: true, // 用于在全局引用方法时标识这一个的文件名 如:user/setUserName  
  state,  
  getters,  
  mutations,  
  actions  
} 

其次完成这两个模块载入,修改 store/index.js代码如下

import Vue from 'vue'  
import Vuex from 'vuex'  
import app from './modules/app'  
import user from './modules/user'  
Vue.use(Vuex)  
export default new Vuex.Store({  
   modules: {  
    app, 
    user  
  }  
})  

这样比把所有的状态写到一起,更好的完成了维护。使用时和上面的使用方法一致,仅需增加模块的名称而已。代码如下

<template>  
  <div class="hello">  
    <h1>项目名称:{{ getAppName }}</h1>  
    <h1>项目名称:{{ mapAppName }}</h1>  
    <h1>用户名称:{{ getUserName }}</h1>  
  </div>  
</template>  
<script>  
export default {  
  name: 'hello',   
  computed: {  
    getAppName () {  
      return this.$store.state.app.appName  
    },  
    getUserName () {  
      return this.$store.state.user.userName  
    },  
  }
}  
</script>

示例

示例界面如下图,特别丑陋,仅为了说明问题
在这里插入图片描述
写三个组件,分别是使用data接收state和getters数据(DataShow.vue)、使用computed接收state和getters数据(ComputeShow.vue),通过输入框输入的数据增加(减少)state内容(CountChange.vue)。通过该示例体会state、getters、mutations和Actions对象的使用。
组件DataShow代码

<template>
  <div align="center" style="background-color:aliceblue;">
    <p>以下是使用Data直接获取stores中的状态数据,状态数据发生变化时,该部分数据不同步刷新</p>
    <h1>使用data接收  state:{{ dataState }}</h1>
    <h1>使用data接收Getters:{{ dataGetters }}</h1>
  </div>
</template>

<script>
  export default {
    name: 'DataShow',
    data() {
      return {
        dataState: this.$store.state.count,
        dataGetters: this.$store.getters.getChangeValue
      }
    }
  }
</script>

<style>
</style>

使用Data直接获取state和getters中的状态数据,状态数据发生变化时,该部分数据不同步刷新。
组件ComputeShow代码

<template>
  <div align="center" style="background-color: bisque;">
    <p>以下是使用computed直接获取stores中的状态数据,状态数据发生变化时,同步刷新</p>
    <h1>使用computed接收 state:{{ computedState }}</h1>
    <h1>使用computed接收Getters:{{ computedGetters }}</h1>
  </div>
</template>

<script>
  export default {
    name: 'ComputeShow',
    computed: {
      computedState() {
        return this.$store.state.count; //通过$store.getters获取相应结果
      },
      computedGetters() {
        return this.$store.getters.getChangeValue; //通过$store.getters获取相应结果
      },
    }
  }
</script>

<style>
</style>

使用computed获取state和getters中的状态数据,状态数据发生变化时,view同步刷新。

CountChange代码如下

<template>
  <div align="center">
    <input type="number" v-model="paramValue" />
    <button @click="addNum">+增加</button>
    <button @click="subNum">-减少</button>
  </div>
</template>

<script>
 export default {
    name: 'CountChange',
    data() {
      return {
        paramValue: 1,
      }
    },
    methods: {
      addNum() {
        this.$store.dispatch('increment', {
          res: this.paramValue
        })
      },
      subNum() {
        this.$store.commit('decrement', this.num)
      },
    }
  }
</script>

<style>
</style>

变更状态值时,addNum使用了action对象,subNum直接使用mutations提交变化。
stores代码:在src创建stores目录,在该目录下创建index.js文件,内容如下:

import Vue from 'vue'
import Vuex from 'vuex'

//使用vuex模块
Vue.use(Vuex);

//声明静态常量为4
const state = {
  count: 4
};

const getters = {
  getChangeValue(state) {
    return state.count * 100
  }
};

const mutations = {
  add(state, n) {
    console.log(n)
    state.count += n.paramvalue;
  },
  sub(state) {
    state.count--;
  }
};
//这里的actionAdd是组件中和所触发的事件相对应的方法
const actions = {
  increment(context, num) { //context官方给出的指定对象,可以理解为store对象,num代表参数
    context.commit('add', { //这里的add’是mutations中的方法
      paramvalue: num.res //res为传递参数
    })
  },
  decrement(context) {
    context.commit('sub');
  }
};

//导出一个模块
export default new Vuex.Store({
  state,
  getters,
  mutations,
  actions
})

这里定义了一个count,默认值是4,getter给count乘100,mutations完成count值的减少和增加,通过actions代理mutations完成数据的更新。

在main.js中,将stores挂载到根目录下,全局使用,代码如下

import Vue from 'vue'
import App from './App'
import store from './stores'  //导入store

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  store,                //挂载在全局下
  components: { App },
  template: '<App/>'
})

编写页面组件(StoreView.vue),将上述三个组件引入,进行组合,代码如下

<template>
  <div>
    <v-data-show></v-data-show>
    <v-compute-show></v-compute-show>
    <v-count-change></v-count-change>
  </div>
</template>

<script>
  import dataShow from '@/view/DataShow.vue'
  import computeShow from '@/view/ComputeShow.vue'
  import countChange from '@/view/CountChange.vue'
  export default {
    name: 'StoreView',
    components: {
      'v-data-show': dataShow,
      'v-compute-show': computeShow,
      'v-count-change': countChange
    }
  }
</script>

<style>
</style>

更改app.vue,将页面组件挂载app下。

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <div align="left">
      <v-home></v-home>
    </div>
  </div>
</template>

<script>
  import home from '@/view/StroeView.vue'
  export default {
    name: 'App',
    components: {
      'v-home': home
    }
  }
</script>

小结

vuex状态管理器是一种单一状态树,state用于定义和存储状态值,通过this.store.key可以获取到状态值,为了能够做到实时响应,获取state值应该computes中;有时取有变化的状态值时,需要使用到getters对象;状态值的更新不能直接更新,需要使用mutations对象;如果需要异步更新时,使用Actions对象作为mutations的代理对象完成对状态更新。modules对象很简单将store切割若干模块,更易于维护。经过上述内容学习,已经完全会使用vuex进行组件间的通讯与同步,除此之外,vuex还提供了了四个辅助函数,用于简化代码,方便组件使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值