1.前言

在使用Vue进行开发的时候,关于vue组件通信的方式,除了通俗易懂了解Vue组件的通信方式这篇博文谈到三种通信方式,其实vue更提倡我们使用vuex来进行组件间的状态管理以及通信问题。Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。

2.引例

在学习vuex之前,我们不妨先看这样一个例子:

在一个父子组件嵌套环境下,父组件可以改变子组件的背景颜色,而子组件自身也可以改变自己的背景颜色。

虽然使用之前谈到的组件通信方式也可以实现这个例子,但是这不是我们今天想讨论的。

我们可以换个角度看这个例子:

我们可以把子组件的背景颜色看做一种状颜色态,我们把这个颜色状态放在组件的外部,让子组件去读取这个状态来决定自己的背景颜色该是什么,如果父组件需要改变子组件的背景颜色,那么只需让父组件去改变这个状态即可,因为子组件的背景颜色取决于这个颜色状态是什么颜色,控制了这个状态,即控制了子组件的背景颜色。

简而言之一句话:就是需要对状态进行管理,这也就是vuex的核心:状态管理。

3.store

vuex对于状态管理提供了状态仓库store,store的作用就是将所有状态统一存储管理起来,状态仓库store是响应式的,当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。说了这么多,我们简单使用一下store。

3.1 安装vuex

在使用vue-cli进行模块化开发时,使用vuex之前必须先安装vuex:

npm install vuex --save

3.2 创建状态仓库store

安装完成后,在项目中main.js文件中按照如下方式引入vuex并创建一个状态仓库store,在状态仓库store内创建第一个状态color并设置该状态初始值为red:

 import vuex from 'vuex'
Vue.use(vuex);
var store = new vuex.Store({
state:{
color:'red'
}
})

然后,在main.js中的根vue对象中挂载上面创建好的状态仓库store,这样在任何组件中都可以去读取仓库中的状态:

 new Vue({
el: '#app',
store,
render: h => h(App)
})

OK,到这里,状态仓库和状态就创建好了,接下来我们就可以采用读取状态和改变状态的方式来改写上面的例子了,代码如下:

父组件代码:

<template>
<div id="app">
  <h1>我是父组件</h1>  
<!--点击按钮后,去状态仓库将状态color改成yellow-->
<input type="button" value="变成黄色" @click="$store.state.color = 'yellow'">
<Child></Child>
</div>
</template> <script>
import Child from './Child'
export default {
name: 'app',
components:{
Child
},
data () {
return { }
},
}
</script> <style> </style>

子组件代码:

<template>
<!--子组件的backgroundColor属性值取决于状态仓库中的状态color值-->
<div class="child" :style="{backgroundColor:$store.state.color}">
<h1>子组件</h1>
<!--子组件点击按钮,也可以去状态仓库中改变color状态值-->
<input type="button" value="变成蓝色" @click="$store.state.color = 'blue'">
</div>
</template> <script>
export default {
name: "Child",
}
</script> <style scoped>
.child{
width: 500px;
height: 500px;
}
</style>

效果如下:

以上例子就是Vuex最简单的使用,怎么样,是不是so easy!!

3.3  优化代码结构

前面为了方便 , 我们把 store 对象写在了 main.js 里面 , 但实际上为了便于日后的维护 , 我们将store单独隔离出来分开写更好 , 我们在 src 目录下 , 新建一个 store 文件夹 , 然后在里面新建一个 index.js :

import Vue from 'vue'
import vuex from 'vuex'
Vue.use(vuex); export default new vuex.Store({
state:{
color:'red'
}
})

那么相应的 , 在 main.js 里的代码应该改成 :

import Vue from 'vue'
import App from './App.vue'
//引入store
import store from './store'
new Vue({
el: '#app',
store,
render: h => h(App)
})

这样就把 store 单独分离出去了 ,日后当状态越来越多的时候维护起来就更加方便啦!

4.module

虽然我们把 store 单独分离出去了,但是随着项目规模越来越大,组件也越来越多,这就造成store.state里面的状态会越来越多,这么多的状态都堆在store.state里面显然不是一个很好代码结构,更重要的是哪些组件依赖哪些状态也会变得非常不清晰。那有没有什么更好的解决方案呢?其实Vuex早就替我们想到了,Vuex中的modules就是用来解决这个问题的。

modules可以将store.state里面的状态按照各个组件所依赖的情况进行分类,例如,我们将上面例子中子组件Child所依赖的color状态单独写进一个js文件中,然后在store 文件夹下的 index.js 中引入即可,代码如下:

//在store文件夹下新建Child_store.js文件:
export default {
state:{
color:'red'
}
}

然后在store 文件夹下的 index.js 中引入:

import Vue from 'vue'
import vuex from 'vuex'
Vue.use(vuex); import Child_store from './Child_store.js';//引入Child_store.js中的store对象 export default new vuex.Store({
modules: {
Child_store:Child_store
}
})

做出这样的修改之后 , 我们只需将之前我们使用的 $store.state.color 统统改为 $store.state.Child_store.color即可。

如果还有其他的组件所依赖的状态 ,那就在store文件夹下再新建一个对应的xx_store.js文件 , 然后将他们引入到 index.js 文件中的modules中。

import Vue from 'vue'
import vuex from 'vuex'
Vue.use(vuex); import Child_store from './Child_store.js';//引入Child_store.js中的store对象
import xxx_store from './xxx_store.js';//引入xxx_store.js中的store对象 export default new vuex.Store({
modules: {
Child_store:Child_store,
xxx_store :xxx_store
}
})

5. mutation

在上面例子中,我们点击按钮这个动作仅仅依赖了一个color状态,所以我们可以将改变状态的动作直接写在按钮的click的事件中,即@click="$store.state.Child_store.color = 'blue'"。,但是如果按钮点击依赖了多个状态,那么我们就不能把所有状态改变的动作都写在click事件中,当然,也不允许我们这么干。此时我们就需要用到mutations了,mutations允许我们一次性更新多个状态。

例如,我们给上面例子中的子组件Child再新增一个状态width,用来改变子组件的宽度,我们希望当点击按钮,既改变了子组件的背景颜色,而且也改变子组件的宽度,代码如下:

1.给Child_store.js中增加mutations选项

//Child_store.js
export default {
state:{
color:'red',
width:'500px'
},
mutations:{
switch(state,payload){ //这里的state对应着上面那个state
state.color = payload.color;
state.width = payload.width;
}
},
}

在mutations选项中定义switch函数,该函数可以接收两个参数,第一个参数必须是state,即为要改变的状态对象,第二个参数称为载荷(payload),即函数内要使用的参数.

2.子组件代码

<template>
<div class="child" :style="{backgroundColor:$store.state.Child_store.color,width:$store.state.Child_store.width}">
<h1>子组件</h1>
</div>
</template> <script>
export default {
name: "Child",
}
</script> <style scoped>
.child{
height: 500px;
}
</style>

3.父组件代码

<template>
<div id="app">
<h1>我是父组件</h1>
<input type="button" value="变成蓝色并且宽度变小" @click="$store.commit('switch',{color:'blue',width:'100px'})">
<Child></Child>
</div>
</template> <script>
import Child from './Child'
export default {
name: 'app',
components:{
Child
},
data () {
return {
}
}
}
</script> <style> </style>

父组件中使用$store.commit('switch',{color:'blue',width:'100px'})来触发mutations中的switch函数,$store.commit()接收的第一个参数为要触发的mutations中的哪个函数,第二个参数是一个对象,也就是要触发的switch函数中的载荷payload。

效果如下:

6.action

多个state的操作 , 使用mutations会来触发会比较好维护 , 那么需要执行多个mutations就需要用action了:

1.给Child_store.js中增加actions选项

export default {
state:{
color:'red',
width:'500px'
},
mutations:{
switch(state,payload){ //这里的state对应着上面那个state
state.color = payload.color;
state.width = payload.width;
}
},
actions:{
switch_action(ctx,payload){ //这里的ctx和我们使用的$store拥有相同的对象和方法
ctx.commit('switch',payload);
//你还可以在下面触发其他的mutations方法
}
}
}

2.子组件不用变,在父组件中需要使用$store.dispatch('switch_action',{color:'blue',width:'100px'})来触发actions中的switch_action方法

<template>
<div id="app">
<h1>我是父组件</h1>
<input type="button" value="变成蓝色并且宽度变小" @click="$store.dispatch('switch_action',{color:'blue',width:'100px'})">
<Child></Child>
</div>
</template> <script>
import Child from './Child'
export default {
name: 'app',
components:{
Child
},
data () {
return {
}
}
}
</script> <style> </style>

7.getter

有时候我们需要从state 中派生出一些状态,也就是说,某些状态是通过现有的一个或多个状态通过计算得到的,类似于计算属性computed。假如我们现有一个状态show:true,但是我们很多地方又需要一个跟show状态相反的notShow状态,这种情况放在以前,我们会写一个计算属性来返回notShow:

computed(){
not_show(){
return !this.$store.state.show;
}
}

哪个组件里需要notShow状态,就在哪个组件里写一遍上面的代码,如果需要这个状态的组件很多,那么就需要写很多遍重复的代码。这肯定不是我们想要的,而Vuex中的getter就很好的解决了这个问题:

export default {
state:{
show:false
},
getters:{
notShow(state){//这里的state对应着上面这个state
return !state.show;
}
}
}

我们在组件中使用$store.state.show来获得状态show,类似的 , 我们可以使用$store.state.notShow来获得状态notShow。

注意 $store.state.notShow的值是不能直接修改的 , 需要对应的 state 发生变化才能修改。

8.总结

了解了以上这些,再回头去看Vuex的官方文档,就应该不会一脸懵逼啦,哈哈哈哈。

(完)

通俗易懂了解Vuex的更多相关文章

  1. Vue组件间通信方式到底有几种

    1. 前言 Vue的一个核心思想就是组件化.所谓组件化,就是把页面拆分成多个组件 (component),每个组件依赖的 CSS.JavaScript.模板.图片等资源放在一起开发和维护.组件是资源独 ...

  2. Vuex 入门指南

    1.Vuex是什么? 我们还是像以往一样先看一看官方文档对此的解读(Vuex 是什么? · GitBook) Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的 ...

  3. Vuex 通俗版教程

    作者 Yeaseon 已关注 2017.03.16 16:44* 字数 1245 阅读 243评论 2喜欢 4 本文基本上是官方教程的盗版,用通俗易懂的文字讲解Vuex,也对原文内容有删减. 如果你对 ...

  4. 了解Vuex状态管理模式的理解强化指南

    1 Vuex是什么呢?它是Vue的状态管理模式,在使用vue的时候,需要在vue中各个组件之间传递值是很痛苦的,在vue中我们可以使用vuex来保存我们需要管理的状态值,值一旦被改变,所有引用该值的地 ...

  5. vuex , 简单入(liao)门(jie)

    vuex什么 ? 官方的说法就是 vuex是专门为vue.js应用程序开发的 状态管理模式 .并采用集中式存储 , 管理应用的所有组件的状态 ,并以相同的规则保证状态以一种可预估的方式发生变化. 自己 ...

  6. 挑战全网最幽默的Vuex系列教程:第一讲 Vuex到底是什么鬼

    先说两句 官方已经有教程了,为什么还要写这个教程呢?说实话,还真不是我闲着蛋疼,官方的教程真的是太官方了,对于刚入门 Vuex 的童鞋来说,想必看官方的教程,很多地方就如同看圣经一样,比如「欧玛尼玛尼 ...

  7. 挑战全网最幽默的Vuex系列教程:第二讲 Vuex旗下的State和Getter

    先说两句 上一讲 「Vuex 到底是个什么鬼」,已经完美诠释了 Vuex 的牛逼技能之所在(纯属自嗨).如果把 Vuex 比喻成农药里面的刘备,那就相当于你现在已经知道了刘备他是一个会打枪的力量型英雄 ...

  8. 挑战全网最幽默的Vuex系列教程:第三讲 Vuex旗下的Mutation

    写在前面 上一讲「Vuex 旗下的 State 和 Getter」,告诉了我们怎么去使用仓库 store 中的状态数据.当然,光会用肯定还不够,大部分的应用场景还得对这些状态进行操控,那么具体如何操控 ...

  9. Vue学习—— Vuex学习笔记

    组件是Vue最强大的功能之一,而组件实例的作用域是相互独立的,意味着不同组件之间的数据是无法相互使用.组件间如何传递数据就显得至关重要,这篇文章主要是介绍Vuex.尽量以通俗易懂的实例讲述这其中的差别 ...

随机推荐

  1. 【JZOJ5248】花花的聚会

    Description 注意测试数据中道路是 到 的单向道路,与题面恰好相反. Input Output Sample Input 7 7 1 3 1 2 6 7 3 6 3 5 3 4 7 2 3 ...

  2. bugku 程序员本地网站

    提示从本地访问,怎样让服务器认为你是从本地进行访问的: 使用burp抓包并在包中进行修改加入X-Forwarded-For: 127.0.0.1 X-Forwarded-For: 简称XFF头,它代表 ...

  3. 并发新构件之CyclicBarrier

    CyclicBarrier:叫做循环栅栏,名字挺好听的.JDK描述:允许一组线程全部等待彼此达到共同屏障点的同步辅助. 循环阻塞在涉及固定大小的线程方的程序中很有用,这些线程必须偶尔等待彼此. 屏障被 ...

  4. linux ln命令 建立文件夹桌面快捷方式

    指令如下: sudo ln -s /root/myhack/ /root/Desktop 以上指令是创建软链接到桌面. 指令解析: ln -s是创建软链接指令,如果不加-s则是创建硬链接.

  5. Javascript之傻傻理不清的原型链、prototype、__proto__

    新人学习Javascript,其中的原型链一直是云里雾里,不得要领,查了很多相关资料,觉得这遍讲得最为清晰易懂,特转载分享,共同学习. 1. JavaScript内置对象 所谓的内置对象 指的是:Ja ...

  6. css3实现饼状图进度及环形进度条

    1 <!-- 饼图 --> <div class="pie"></div> <hr /> <!-- 环形图 --> &l ...

  7. 前端路由hash、history原理及简单的实践下

    阅读目录 一:什么是路由?前端有哪些路由?他们有哪些特性? 二:如何实现简单的hash路由? 三:如何实现简单的history路由? 四:hash和history路由一起实现 回到顶部 一:什么是路由 ...

  8. Spring 源码阅读之 深入理解 finishBeanFactoryInitialization

    源码入口 上篇博文中我们看到了将Spring环境中的 BeanPostProcessor找出来,添加到BeanFactory中的beanPostProcessors中,统一维护,本片博文继续往下拓展, ...

  9. Excel接口导出,导入数据库(.Net)

    public ActionResult TestExcel(string filePath) { return View(); } /// <summary> /// 根据Excel列类型 ...

  10. Java日志Log4j或者Logback的NDC和MDC功能

    NDC和MDC的区别 Java中使用的日志的实现框架有很多种,常用的log4j和logback以及java.util.logging,而log4j是apache实现的一个开源日志组件(Wrapped ...