Vuex的使用以及案例

举报
tea_year 发表于 2022/01/21 17:37:34 2022/01/21
【摘要】 我们知道组件之间是独立的,组件之间想要实现通信,我目前知道的就只有props选项,但这也仅限于父组件和子组件之间的通信。如果兄弟组件之间想要实现通信呢?当我们做中大型项目时,面对一大堆组件之间的通信,还有一大堆的逻辑代码,会不会很抓狂?那为何不把组件之间共享的数据给提取出来,在一定的规则下管理这些数据呢? 这就是Vuex的基本思想了。13.1 Vuex简介什么是Vuex?官方说法:Vuex ...

我们知道组件之间是独立的,组件之间想要实现通信,我目前知道的就只有props选项,但这也仅限于父组件和子组件之间的通信。如果兄弟组件之间想要实现通信呢?当我们做中大型项目时,面对一大堆组件之间的通信,还有一大堆的逻辑代码,会不会很抓狂?那为何不把组件之间共享的数据给提取出来,在一定的规则下管理这些数据呢? 这就是Vuex的基本思想了。

13.1 Vuex简介

什么是Vuex?官方说法:Vuex 是一个专为 Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。简单来说vuex是vue的一个插件,用来实现组件之间数据通讯的。

想要了解Vuex的功能,重点是理解什么是状态管理,我们这里使用一个计数器的小应用进行知识点的引入。现有一个页面点击的计数器,伪代码如下。

new Vue({

// state

data () {

return {

count: 0

}

},

// view

template: `

<div>{{ count }}</div>

`,

// actions

methods: {

increment () {

this.count++

}

}

})

这个小应用中有三个重要的部分:

• state,驱动应用的数据源;

• view,以声明方式将 state 映射到视图;

• actions,响应在 view 上的用户输入导致的状态变化。

三个部分组成了一个简单的计数器,他们之间的关系我们可以叫做“单向数据流”。如图13.1所示。


图13.1 单向数据流

state作为我们的数据,展示在view视图中,视图中的针对用户的操作进行相应,调用执行了函数,也就是actions,接下来actions的函数又对我们的数据也就是state进行了改变,在整个流程中三个部分之间的目前来说是一一对应的,也就是说state只显示在一个view视图上,也只被一个action的函数所改变,所以称之为单向数据流。那么如果我们的需求发生了变化,我们不仅仅要在某个页面进行计数,我们要求这个计数的总数是全局共享的,也就是在所有的页面中都可以改变state的值。这个时候就出现了一个问题:当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏。体现在多个视图依赖于同一状态,以及来自不同视图的行为需要变更同一状态。

因此,我们为什么不把组件的共享状态抽取出来,以一个全局单例模式管理呢?在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为,这种模式就是状态管理。vuex就是vue中实现状态管理的插件。

13.2 Vuex入门

理解什么是Vuex之后我们直接来上手实际演示一下Vuex如何使用。Vuex的使用场景大多是大型的单页面应用,因为此时很可能需要使用到组件外部管理状态。废话不多说,我们开始学习Vuex的使用。

13.2.1 搭建Vue应用

首先使用vue-cli来构建一个vue的开发环境,项目取名为vuex_demo。这里主要使用的知识点是vue-cli,使用vue create vuex_demo命令完成创建。之前章节已经有过对脚手架的学习,这里不再详细介绍。

13.2.2 安装vuex

vuex有多种安装方式,我们这里介绍其中两种,分别是直接下载 /CDN 引用,以及nmp命令。实际项目中建议使用命令nmp命令的方式。

• 直接下载 / CDN 引用

在 Vue 之后引入 vuex 会进行自动安装:

<script src="/path/to/vue.js"></script>

<script src="/path/to/vuex.js"></script>

• NPM

npm install vuex --save


进入vuex_demo应用下执行npm install vuex --save命令后,打开package.json文件,在dependencies中找到vuex的依赖就表明安装成功,如图13.2所示。

图13.2 package.json


13.2.3 编写代码

我们当前应用完成一个简单的计数器,页面中包含当前点击次数,默认为0,以及一个按钮,每点击一次安装计数器的值加一。

我们在src目录下新建store文件夹,store表示存储的意思,我们使用vuex来存储一些共享的信息。并且在store文件夹中vuex.js文件,此文件用于vuex插件的实例化。Vuex.js文件代码如例13-1所示。

例13-1 vuex.js

1 //引入模块

2 import Vue from 'vue'

3 import Vuex from 'vuex'

4 //在一个模块化的打包系统中,您必须显式地通过 `Vue.use()` 来安装 Vuex:

5 Vue.use(Vuex)

6

7 //#实例化Vuex.store ,并进行相关配置

8 export default new Vuex.Store({

9 //存储状态

10 state: {

11 count: 0

12 },

13 //其中定义函数,用于变更store中的状态

14 mutations: {

15 increment (state) {

16 console.log('执行了递增')

17 state.count++

18 }

19 }

20 })


接下来我们还需要修改main.js文件,在vue实例中添加store选项。main.js文件关键代码如例13-2所示。

例13-2 main.js

1 import Vue from 'vue'

2 import App from './App.vue'

3 //引入vuex.js模块

4 import Store from './store/vuex'

5

6 Vue.config.productionTip = false

7

8 new Vue({

9 //配置store选项

10 store:Store,

11 render: h => h(App),

12 }).$mount('#app')


最后我们修改App.vue文件,在其中操作如何展示state的值,以及触发器递增,App.vue代码如例12-2所示。

例12-3 App.vue

1 <template>

2 <div id="app">

3 count:

4 <!-- $store获取到vue实例存储选项中保存在state中的count的值进行显示 -->

5 <h1>{{ $store.state.count }}</h1>

6 <!--点击按钮触发increment函数-->

7 <button @click="increment">点击</button>

8 </div>

9 </template>

10

11 <script>

12

13

14 export default {

15 name: 'App',

16 methods:{

17 increment:function(){

18 //调用当前vue应用实例的store选项,并且执行函数名为increment的函数

19 this.$store.commit('increment')

20 }

21 }

22

23 }

24 </script>

25

26 <style>

27 #app {

28 font-family: Avenir, Helvetica, Arial, sans-serif;

29 -webkit-font-smoothing: antialiased;

30 -moz-osx-font-smoothing: grayscale;

31 text-align: center;

32 color: #2c3e50;

33 margin-top: 60px;

34 }

35 </style>

36

37

13.2.3 运行项目

运行项目之后可以看到页面中显示了定义在store中state里定义的count的值,默认为0,运行效果如图13.3所示。



图13.3 运行结果1

在点击按钮之后count的值随着点击次数递增并且显示在页面中,点击3次按钮后效果如果13.4所示。

图13.4 运行结果2



13.2.4 代码解释

以上代码中关键的步骤:

• 使用vuex模块,初始化Vuex.Store实例,配置state,mutations选项。

• 配置main.js,使全局的vue实例配置store选项,添加对vuex的使用。

• 页面中应用state的值,已经触发mutations函数改变state的值。

当然当前的配置并不完整,针对Vuex.store实例化的完整配置如下。


#实例化Vuex.store ,并进行相关配置

export default new Vuex.Store({

state: {

//存储状态

},

mutations: {

//变更store中的状态

},

actions: {

//类似于mutation,

//action提交的是mutation,而不是直接变更状态

//action可以包含异步操作

},

getters:{

//state的派生状态

},

modules: {

//将store分割成模块

}

})

我们发现,在VueX对象中,其实不止有state,还有用来操作state中数据的方法集,以及当我们需要对state中的数据需要加工的方法集等等成员,成员列表:

• state 存放状态

• mutations state成员操作

• getters 加工state成员给外界

• actions 异步操作

• modules 模块化状态管理

成员之间相互配合的流程如图13.5所示。

图13.5 vuex流程


首先,Vue组件如果调用某个VueX的方法过程中需要向后端请求时或者说出现异步操作时,需要调用VueX中actions的方法,如果没有异步操作,那么我们就可以直接在组件内提交状态中的Mutations中自己编写的方法来达成对state成员的操作,最后被修改后的state成员会被渲染到组件的位置当中去。


13.3 state访问状态对象

state用于存储共享状态,我们可以在其中保存共享数据,他是全局的,在任意组件中都可以通过this.$store.state.属性名获取对应的状态数值。


#存储共享状态

state:{

num:100,

userinfo:{}

}


#组件中

#通过在根实例中注册 store 选项,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$store 访问到

#由于 Vuex 的状态存储是响应式的,从 store 实例中读取状态最简单的方法就是在计算属性中返回某个状态

computed:{

    num(){

        return this.$store.state.num;

    }

},


13.4 mutations修改状态

mutations是操作state数据的方法的集合,比如对该数据的修改、增加、删除等等。

13.4.1 mutations使用方法

mutations中的方法都有默认的形参:

([state] [,payload])

• state是当前VueX对象中的state

• payload是该方法在被调用时传递参数使用的

比如我们刚才写的案例中,只使用了state一个参数:

//#实例化Vuex.store ,并进行相关配置

export default new Vuex.Store({

//存储状态

state: {

count: 0

},

//其中定义函数,用于变更store中的状态

mutations: {

increment (state) {

console.log('执行了递增')

state.count++

}

}

})


组件中如果想要改变state中的某个值,不能获取值之后直接赋值,需要调用mutations中的函数的方式进行对state中值改变的操作。commit中的字符串参数就是mutations中定义的函数的函数名。

this.$store.commit('increment')

13.4.2 mutations传递参数

如果我们每次count的值不是递增,而是指定数值大小的递增,此时就需要使用额外的参数,此时可以使用payload参数。

vuex.Store初始化部分的代码如下。


mutations: {

//第二个参数用于传值

increment (state,payload) {

// 变更状态

//state.num++

state.num+=payload

}

}

组件中调用代码如下。

methods:{

increment(){

//第一个参数指定执行mutations中的哪一个函数,第二个参数是执行函数时候传递的参数

this.$store.commit('increment',45);

}

}

注意一条重要的原则就是要记住 mutation 必须是同步函数。

13.5 getters计算过滤操作

有时候我们需要从 store 中的 state 中派生出一些状态,例如对列表进行过滤并计数。Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

Getters中的方法有两个默认参数:

• state 当前VueX对象中的状态对象。

• getters 当前getters对象,用于将getters下的其他getter拿来用。

比如我们要对保存在state中的student数组数据进行过滤,这返回30岁以下的数据。此时就可以使用getters接受state作为第一个参数,对state中的数据进行过滤,二次处理。

//vuex实例化

getters:{

//过滤年龄小于30

filter_age(state){

return state.student.filter(item => item.age<30);

}

}


//组件中获取过滤后的数据

//Getters 会暴露为 store.getters 对象,你可以以属性的形式访问这些值

this.$store.getters.filter_age

13.6 actions异步修改状态

actions和之前讲的Mutations功能基本一样,不同点是,actions是异步的改变state状态,而Mutations是同步改变状态。

在实例化路由时对actions进行设置语法如下,在actions的函数中调用mutations里的函数。我们会发现这actions和mutations的中的方法传递的参数也不一样,这里是context,表示上下文对象,这里你可以理解称store本身。

actions: {

increment (context) {

context.commit('increment')

}

}


在组件中调用actions中函数的方式也与mutation调用不同,actions函数执行通过store.dispatch()触发,调用方式如下。


//Action 通过 store.dispatch 方法触发:

store.dispatch('increment')


13.7 module模块组

随着项目的复杂性增加,我们共享的状态越来越多,这时候我们就需要把我们状态的各种操作进行一个分组,分组后再进行按组编写。module:状态管理器的模块组操作。

也就是说由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:

#moduleA.js

const moduleA = {

state: () => ({ xx }),

mutations: { ... },

actions: { ... },

getters: { ... }

}

export default moduleA;


#modulesB.js

const moduleB = {

state: () => ({ ... }),

mutations: { ... },

actions: { ... }

}


#index.js

import moduleA from './moduleA.js'

const store = new Vuex.Store({

modules: {

a: moduleA,

b: moduleB

}

})

//使用:this.$store.state.a.xx

13.8 本章小结

• Vuex 是一个专为 Vue.js应用程序开发的状态管理模式。

• 使用命令npm install vuex --save完成vuex的安装

• 代码上vuex中通过实例化Vuex.store ,并进行相关配置来实现状态管理。

• Vuex 实例化时包含state,mutations,actons,getters,module选项。

• state用于存储共享状态,我们可以在其中保存共享数据。在任意组件中都可以通过this.$store.state.属性名

• mutations是操作state数据的方法的集合,比如对该数据的修改、增加、删除等等。

• mutations中的方法都有默认的形参:([state] [,payload]),state是当前VueX对象中的state,payload是该方法在被调用时传递参数使用的。

• Vuex 允许我们在 store 中定义“getter”属性来实现对数据的过滤。

• actions和之前讲的Mutations功能基本一样,不同点是,actions是异步的改变state状态,而Mutations是同步改变状态。

3.9 理论习题与实践练

1.思考题

1.1 请简述你是怎么理解状态管理的。

1.2 请思考状态管理的使用场景。

1.3 请简述vuex的使用步骤。

1.4 请简述Vue.Store对象实例化所需要的选项都有哪些?

1.5 请简述如何获取读取state中某个数据的值。

1.6 请简述通过mutations实现对state中数据的值的改变。

2.编程题

• 2.1. 使用vuex实现购物车数据的保存功能



【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。