SpringBoot + Vue(十三)VueX状态管理库

对于组件化开发来说,大型应用的状态往往跨越多个组件。在多层嵌套的父子组件之间传递状态十分麻烦,而Vue更是没有为兄弟组件提供直接共享数据的方法。

基于这个问题,许多框架提供了解决方案:使用全局的状态管理器,将所有分散的共享数据交由状态管理器保管,Vue也不例外。

VueX 是专为Vue.js 应用程序开发的状态管理库,采用集中式存储来管理应用的所有组件状态。

VueX 用于管理分散在Vue各个组件中的数据。兄弟组件间的数据传递。

vuex有两个版本,分别vuex3对应vue2 ; vuex4对应vue3

两种版本安装方式:

vuex3安装:npm install vuex@3

vuex4安装:npm install vuex

官方网站: https://v3.vuex.vuejs.org/zh/

关于状态管理:

一般在复杂应用中才会用到VueX ,并非必须的。

每一个VueX应用的核心都是一个store (仓库)全局对象,与普通的全局对象不同,基于Vue数据与视图绑定的特点,当store中的状态(数据)发生变化时,与之绑定的视图也会被重新渲染。

store中的状态不允许被直接修改,改变store中的状态的唯一途径就是显式提交(commit)mutation,这可以方便地跟踪每一个状态的变化。

在大型复杂应用中,如果无法有效跟踪到状态的变化,将会对理解和维护代码带来极大困扰

VueX中有5个重要概念:State、Getter、Mutation、Action、Module

下面进行演示

创建一个基于 Vue2 的新项目:具体创建方式详见笔记(九)

vue create vuex-demo

将刚刚创建的项目 vuex-demo 拖入 Visual Studio Code 中

vuex3安装:npm install vuex@3

在src目录下新建一个 store 文件夹,新建一个 index.js 文件,提供一个初始 state 对象和一些 mutation,文件代码如下:

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

const store = new Vuex.Store({
 state: {
 count: 0
 },
 mutations: {
 increment (state) {
 state.count++
 }
 }
})

说明:建立了一个store(仓库),默认count初始值为: 0 ;以后state 是状态就是给各个组件调用的。

不能直接改state的状态,如需要修改要调用 mutations 方法(该方法是用于 +1 操作)。

然后将store 导出,这样就可以在main.js中使用了

export default store



现在希望在组件中调用 count 的值,具体操作如下:

1.由于我们是在main.js创建Vue的,因此在main.js 中就可以导入刚刚创建的 index.js

import store from './store/index.js'

由于是以index.js作为文件名,也可以简写省略

import store from './store'

然后用Vuex 提供的一个从根组件向所有子组件,以 store 选项的方式“注入”该 store 的机制:

new Vue({
 render: h => h(App),
 store:store
}).$mount('#app')
做完这些就可以在任意组件中利用store对象去取值。
2.新建一个Test.vue 组件,代码如下:

在根组件App.vue中进行注册


在这个Test.vue 中将 count 的值取出来。

{{ this.$store.state.count }}

运行项目后,浏览器就可以显示出 count 的初始值 :“0”。这个时候Test.vue 组件就成功调用了全局状态值。


如何修改状态码?增加一个按钮,进行加1操作。

定义add方法:

methods:{
 add(){
 this.$store.commit("increment")
 }
 }

再次强调,我们通过提交 mutation 的方式,而非直接改变 store.state.count,是因为我们想要更明确地追踪到状态的变化。

这里调用的是index.js 中 store里面的 increment 方法来进行修改操作,而不是用 this.$store.state.count = this.$store.state.count +1

在浏览器中点击 +1 按钮就可以改变状态了


优化1:可以通过设置一个方法,然后就可以直接调用 {{ count }}

computed: {
 count () {
 return this.$store.state.count
 }
 },

优化2:mapState 辅助函数生成计算属性

当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性,让你少按几次键。

当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给 mapState 传一个字符串数组。

// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'
computed: mapState([
 // 映射 this.count 为 store.state.count
 'count'
])


有时候我们需要从 store 中的 state 中派生出一些状态,例如对state 数据进行过滤并进行计数等处理。

下面进行演示,在state 中再增加一个 todos 待办事项列表。其中,吃饭已经完成;睡觉尚未完成。

todos: [
 { id: 1, text: '吃饭', done: true },
 { id: 2, text: '.睡觉', done: false }
 ]

假设要显示到 Test.vue 组件上,现将 todos 映射过来,然后就可以使用。

现在假设只是想显示已经完成的动作,该怎样操作?

这就需要对 todos 进行过滤。在 index.js 中增加一个 getters 方法(注意:两个方法之间要加逗号 “ , ”)

getters: {
 doneTodos: state => {
 return state.todos.filter(todo => todo.done)
 }
 }

然后就可以在Test.vue 组件中使用 mapGetters 辅助函数来映射。

由于我们原来已经使用了 mapState ,现在又要同时用另外一个方法 mapGetters 就需要对代码进行一些修改:

computed:{
 ...mapState([
 'count','todos'
 ]),
 ...mapGetters([
 'doneTodos'
 ])
 },

这时浏览器就过滤出 done 状态为 true 的数据


下面的Mutation、Action、Module 后面的实例讲解中才能更好理解,在此仅作为了解。

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。

组件中提交 Mutation的方法,代码如下。不再此进行演示,有兴趣可以自己试一下。

import { mapMutations } from 'vuex'

export default {
 // ...
 methods: {
 ...mapMutations([
 'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`


 // `mapMutations` 也支持载荷:
 'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
 ]),
 ...mapMutations({
 add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
 })
 }}


在 mutation 中处理混合异步调用时就要用到 Action 。(在 Vuex 中,mutation 都是同步事务

先注册一个简单的 action:

const store = new Vuex.Store({
 state: {
 count: 0
 },
 mutations: {
 increment (state) {
 state.count++
 }
 },
 actions: {
 increment (context) {
 context.commit('increment')
 }
 }})

在组件中分发 Action ,与前面类似:methods 中使用 mapActions

import { mapActions } from 'vuex'

export default {
 // ...
 methods: {
 ...mapActions([
 'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`

 // `mapActions` 也支持载荷:
 'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
 ]),
 ...mapActions({
 add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
 })
 }}

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。

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 的状态


最终所有模块都要和到一起。当我们创建 Vuex.Store 时,通过 modules 参数给模块起名字,比如:给 moduleA 取名为 a 。

需要访问的模块的时候就加上 a 。store.state.a // -> moduleA 的状态。

其实就是对模块进行分割管理,比如:用户模块的状态,订单模块的状态等分别设置。

上述仅为 Vuex 的基本概念,具体使用到后面的综合案例再具体演示。

展开阅读全文

页面更新:2024-04-25

标签:状态   全局   函数   组件   模块   对象   代码   方式   方法   数据

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top