一. 什么是Vuex?

Vuex

Vuex是一个专门为Vue.js应用程序开发的状态管理模式, 它采用集中式存储管理所有组件的公共状态, 并以相应的规则保证状态以一种可预测的方式发生变化.

Vuex核心

上图中绿色虚线包裹起来的部分就是Vuex的核心, state中保存的就是公共状态, 改变state的唯一方式就是通过mutations进行更改. 可能你现在看这张图有点不明白, 等经过本文的解释和案例演示, 再回来看这张图, 相信你会有更好的理解.

二. 为什么要使用Vuex?

试想这样的场景, 比如一个Vue的根实例下面有一个根组件名为App.vue, 它下面有两个子组件A.vueB.vue, App.vue想要与A.vue或者B.vue通讯可以通过props传值的方式, 但是如果A.vueB.vue之间的通讯就很麻烦了, 他们需要共有的父组件通过自定义事件进行实现, A组件想要和B组件通讯往往是这样的:

组件通讯

  • A组件说: "报告老大, 能否帮我托个信给小弟B" => dispatch一个事件给App
  • App老大说: "包在我身上, 它需要监听A组件的dispatch的时间, 同时需要broadcast一个事件给B组件"
  • B小弟说: "信息已收到", 它需要on监听App组件分发的事件

这只是一条通讯路径, 如果父组件下有多个子组件, 子组件之间通讯的路径就会变的很繁琐, 父组件需要监听大量的事件, 还需要负责分发给不同的子组件, 很显然这并不是我们想要的组件化的开发体验.

Vuex就是为了解决这一问题出现的

三.如何引入Vuex?

  1. 下载vuex: npm install vuex --save
  2. main.js添加:
import Vuex from 'vuex'Vue.use( Vuex );const store = new Vuex.Store({//待添加
})new Vue({el: '#app',store,render: h => h(App)
})

四. Vuex的核心概念?

在介绍Vuex的核心概念之前, 我使用vue-cli初始化了一个demo, 准备以代码的形式来说明Vuex的核心概念, 大家可以在github上的master分支进行下载.这个demo分别有两个组件ProductListOne.vueProductListTwo.vue, 在App.vuedatat中保存着共有的商品列表, 代码和初始化的效果如下图所示:

初始化效果

//App.vue中的初始化代码<template>
<div id="app"><product-list-one v-bind:products="products"></product-list-one><product-list-two v-bind:products="products"></product-list-two>
</div>
</template><script>
import ProductListOne from './components/ProductListOne.vue'
import ProductListTwo from './components/ProductListTwo.vue'export default {name: 'app',components: {'product-list-one': ProductListOne,'product-list-two': ProductListTwo},data () {return {products: [{name: '鼠标', price: 20},{name: '键盘', price: 40},{name: '耳机', price: 60},{name: '显示屏', price: 80}]}}
}
</script><style>
body{font-family: Ubuntu;color: #555;
}
</style>
//ProductListOne.vue
<template><div id="product-list-one"><h2>Product List One</h2><ul><li v-for="product in products"><span class="name">{{ product.name }}</span><span class="price">${{ product.price }}</span></li></ul></div>
</template><script>
export default {props: ['products'],data () {return {}}
}
</script><style scoped>
#product-list-one{background: #FFF8B1;box-shadow: 1px 2px 3px rgba(0,0,0,0.2);margin-bottom: 30px;padding: 10px 20px;
}
#product-list-one ul{padding: 0;
}
#product-list-one li{display: inline-block;margin-right: 10px;margin-top: 10px;padding: 20px;background: rgba(255,255,255,0.7);
}
.price{font-weight: bold;color: #E8800C;
}
</style>
//ProductListTwo.vue
<template><div id="product-list-two"><h2>Product List Two</h2><ul><li v-for="product in products"><span class="name">{{ product.name }}</span><span class="price">${{ product.price }}</span></li></ul></div>
</template><script>
export default {props: ['products'],data () {return {}}
}
</script><style scoped>
#product-list-two{background: #D1E4FF;box-shadow: 1px 2px 3px rgba(0,0,0,0.2);margin-bottom: 30px;padding: 10px 20px;
}
#product-list-two ul{padding: 0;list-style-type: none;
}
#product-list-two li{margin-right: 10px;margin-top: 10px;padding: 20px;background: rgba(255,255,255,0.7);
}
.price{font-weight: bold;color: #860CE8;display: block;
}
</style>

核心概念1: State

state就是Vuex中的公共的状态, 我是将state看作是所有组件的data, 用于保存所有组件的公共数据.

  • 此时我们就可以把App.vue中的两个组件共同使用的data抽离出来, 放到state中,代码如下:
//main.js
import Vue from 'vue'
import App from './App.vue'
import Vuex from 'vuex'Vue.use( Vuex )const store = new Vuex.Store({state:{ products: [{name: '鼠标', price: 20},{name: '键盘', price: 40},{name: '耳机', price: 60},{name: '显示屏', price: 80}]}
})new Vue({el: '#app',store,render: h => h(App)
})
  • 此时,ProductListOne.vueProductListTwo.vue也需要做相应的更改
//ProductListOne.vue
export default {data () {return {products : this.$store.state.products //获取store中state的数据}}
}
//ProductListTwo.vue
export default {data () {return {products: this.$store.state.products //获取store中state的数据}}
}
  • 此时的页面如下图所示, 可以看到, 将公共数据抽离出来后, 页面没有发生变化.

    state效果

到此处的Github仓库中代码为: 分支code01

核心概念2: Getters

我将getters属性理解为所有组件的computed属性, 也就是计算属性. vuex的官方文档也是说到可以将getter理解为store的计算属性, getters的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

  • 此时,我们可以在main.js中添加一个getters属性, 其中的saleProducts对象将state中的价格减少一半(除以2)
//main.js
const store = new Vuex.Store({state:{products: [{name: '鼠标', price: 20},{name: '键盘', price: 40},{name: '耳机', price: 60},{name: '显示屏', price: 80}]},getters:{ //添加getterssaleProducts: (state) => {let saleProducts = state.products.map( product => {return {name: product.name,price: product.price / 2}})return saleProducts;}}
})
  • productListOne.vue中的products的值更换为this.$store.getters.saleProducts
export default {data () {return {products : this.$store.getters.saleProducts }}
}
  • 现在的页面中,Product List One中的每项商品的价格都减少了一半

getters效果

到此处的Github仓库中代码为: 分支code02

核心概念3: Mutations

我将mutaions理解为store中的methods, mutations对象中保存着更改数据的回调函数,该函数名官方规定叫type, 第一个参数是state, 第二参数是payload, 也就是自定义的参数.

  • 下面,我们在main.js中添加mutations属性,其中minusPrice这个回调函数用于将商品的价格减少payload这么多, 代码如下:
//main.js
const store = new Vuex.Store({state:{products: [{name: '鼠标', price: 20},{name: '键盘', price: 40},{name: '耳机', price: 60},{name: '显示屏', price: 80}]},getters:{saleProducts: (state) => {let saleProducts = state.products.map( product => {return {name: product.name,price: product.price / 2}})return saleProducts;}},mutations:{ //添加mutationsminusPrice (state, payload ) {let newPrice = state.products.forEach( product => {product.price -= payload})}}
})
  • ProductListTwo.vue中添加一个按钮,为其添加一个点击事件, 给点击事件触发minusPrice方法
//ProductListTwo.vue
<template><div id="product-list-two"><h2>Product List Two</h2><ul><li v-for="product in products"><span class="name">{{ product.name }}</span><span class="price">${{ product.price }}</span></li><button @click="minusPrice">减少价格</button> //添加按钮</ul></div>
</template>
  • ProductListTwo.vue中注册minusPrice方法, 在该方法中commitmutations中的minusPrice这个回调函数
    注意:调用mutaions中回调函数, 只能使用store.commit(type, payload)
//ProductListTwo.vue
export default {data () {return {products: this.$store.state.products}},methods: {minusPrice() {this.$store.commit('minusPrice', 2); //提交`minusPrice,payload为2}}
}
  • 添加按钮, 可以发现, Product List Two中的价格减少了2, 当然你可以自定义payload,以此自定义减少对应的价格.

    mutations效果

    (Product List One中的价格没有发生变化, 是因为getters将价格进行了缓存)

到此处的Github仓库中代码为: 分支code03

核心概念4: Actions

actions 类似于 mutations,不同在于:

  • actions提交的是mutations而不是直接变更状态

  • actions中可以包含异步操作, mutations中绝对不允许出现异步

  • actions中的回调函数的第一个参数是context, 是一个与store实例具有相同属性和方法的对象

  • 此时,我们在store中添加actions属性, 其中minusPriceAsync采用setTimeout来模拟异步操作,延迟2s执行 该方法用于异步改变我们刚才在mutaions中定义的minusPrice

//main.js
const store = new Vuex.Store({state:{products: [{name: '鼠标', price: 20},{name: '键盘', price: 40},{name: '耳机', price: 60},{name: '显示屏', price: 80}]},getters:{saleProducts: (state) => {let saleProducts = state.products.map( product => {return {name: product.name,price: product.price / 2}})return saleProducts;}},mutations:{minusPrice (state, payload ) {let newPrice = state.products.forEach( product => {product.price -= payload})}},actions:{ //添加actionsminusPriceAsync( context, payload ) {setTimeout( () => {context.commit( 'minusPrice', payload ); //context提交}, 2000)}}
})
  • ProductListTwo.vue中添加一个按钮,为其添加一个点击事件, 给点击事件触发minusPriceAsync方法
<template><div id="product-list-two"><h2>Product List Two</h2><ul><li v-for="product in products"><span class="name">{{ product.name }}</span><span class="price">${{ product.price }}</span></li><button @click="minusPrice">减少价格</button><button @click="minusPriceAsync">异步减少价格</button> //添加按钮</ul></div>
</template>
  • ProductListTwo.vue中注册minusPriceAsync方法, 在该方法中dispatchactions中的minusPriceAsync这个回调函数
export default {data () {return {products: this.$store.state.products}},methods: {minusPrice() {this.$store.commit('minusPrice', 2);},minusPriceAsync() {this.$store.dispatch('minusPriceAsync', 5); //分发actions中的minusPriceAsync这个异步函数}}
}
  • 添加按钮, 可以发现, Product List Two中的价格延迟2s后减少了5

    actions效果

到此处的Github仓库中代码为: 分支code04

核心概念5: Modules

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,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 的状态

【相关链接】

  1. 本文代码地址: https://github.com/Lee-Tanghui/Vuex-Demo
  2. Vuex官方文档: https://vuex.vuejs.org/zh-cn/intro.html
  3. Vuex官方案例演示源码: https://github.com/vuejs/vuex/tree/dev/examples

作者:Lee_tanghui
链接:https://www.jianshu.com/p/a804606ad8e9
來源:简书

Vue.js——十分钟入门Vuex相关推荐

  1. 不会几个框架,都不好意思说搞过前端: Vue.js - 60分钟快速入门

    Vue.js--60分钟快速入门 Vue.js是当下很火的一个JavaScript MVVM库,它是以数据驱动和组件化的思想构建的.相比于Angular.js,Vue.js提供了更加简洁.更易于理解的 ...

  2. 2017 Vue.js 2快速入门指南

    注意,据部分读者反映本文水多,怕湿身者勿进.后续推荐详解 Vue & Vuex 实践 2017 Vue.js 2快速入门指南翻译自Vue.js 2 Quickstart Tutorial 20 ...

  3. vue.js的快速入门使用

    1. vue.js的快速入门使用 1.1 vue.js库的下载 vue.js是目前前端web开发最流行的工具库,由尤雨溪在2014年2月发布的. 另外几个常见的工具库:react.js /angula ...

  4. 用D3.js 十分钟实现字符跳动效果

    用D3.js 十分钟实现字符跳动效果 注 本文基于 D3.js 作者 Mike Bostock 的 例子 原文分为三部分, 在这里笔者将其整合为了一篇方便阅读. 该效果基于 D3.js, 主要使用到了 ...

  5. “易语言.飞扬”十分钟入门教程(修订版1,update for EF1.1.0)

    "易语言.飞扬"十分钟入门教程 (修订版1,update for EF1.1.0) 作者:liigo,2007.8.12 本文地址:http://blog.csdn.net/lii ...

  6. 自学python编程免费教程-Python十分钟入门 自学python基础教程送你参考

    python十分钟入门.简介Python是一种动态解释型的编程语言.Python可以在Windows.UNIX.MAC等多种操作系统上使用,也可以在Java..NET开发平台上使用. 特点 1 Pyt ...

  7. js添加class_用D3.js 十分钟实现字符跳动效果

    用D3.js 十分钟实现字符跳动效果 注 本文基于 D3.js 作者 Mike Bostock 的 例子 原文分为三部分, 在这里笔者将其整合为了一篇方便阅读. 该效果基于 D3.js, 主要使用到了 ...

  8. “易语言.飞扬”十分钟入门教程

    "易语言.飞扬"十分钟入门教程 作者:liigo 2007.1.1 原文链接:http://blog.csdn.net/liigo/archive/2007/01/01/14720 ...

  9. Azure IoT Hub 十分钟入门系列 (2)- 使用模拟设备发送设备到云(d2c)的消息

    本文主要分享一个案例: 10分钟- 使用Python 示例代码和SDK向IoT Hub 发送遥测消息 本文主要有如下内容: 了解C2D/D2C消息: 了解IoT Hub中Device的概念 了解并下载 ...

最新文章

  1. 基于快速GeoHash,如何实现海量商品与商圈的高效匹配?
  2. 实践理解计算机启动过程
  3. 如何计算并测量ABAP及Java代码的环复杂度Cyclomatic complexity
  4. _不懂操作?手把手教你如何在linux下搭建FTP
  5. go语言和java比_Go VS Java:一位资深程序员对两种语言的解读
  6. 在Spring Boot中使用 @ConfigurationProperties 注解, @EnableConfigurationProperties
  7. oracle下载历史版本,ORACLE老版本下载地址
  8. procc 编程需要oracle11.lib,AVProVideo Pro 1.7.3版本 1.7.3属于稳定版本 (官网最新版1.9.1)...
  9. 在线视频下载10个妙招方法大全
  10. IE浏览器无法打开网页
  11. 怎样获取网页视频下载链接
  12. leetcode146. LRU Cache
  13. mjpeg stream 和FFmpeg视频图像读取分析
  14. 【Linux】Linux的内核空间(低端内存、高端内存)
  15. UOJ224 NOI2016 旷野大计算 构造、造计算机
  16. 【 同 余 定 理 (补充)】
  17. jvm探秘五:Class类文件结构之属性表
  18. 我的世界服务器武器修改器,我的世界武器修改器
  19. 世界最有名的十大思想实验
  20. 用Exchange 2000开发企业办公自动化系统

热门文章

  1. solr源码分析之searchComponent
  2. apache kafka源码分析-Producer分析---转载
  3. 深入了解ibatis源码----简单ibatis示例代码
  4. python评分卡建模-卡方分箱(2)之代码实现
  5. Vue 里的$如何理解
  6. Yongkil Kwon:EOS具有当今世界上最多中心化的协议 | 独家专访
  7. https://github.com/fendouai/Awesome-Chatbot
  8. 微软亚洲研究院刘铁岩博士:迎接深度学习的“大”挑战(一)
  9. 详解OS X和iOS图像处理框架Core Image
  10. leetcode - two-sum