Vuex 学习笔记

Vuex 是什么?

Vuex 是一个专为 Vue.js应用程序开发的状态管理模式。由于SPA应用的模块化,每个组件都有它各自的数据(state)、视图(view)和方法(actions),当项目内容越来越多时,每个组件中的状态就变得很难管理。Vuex 就是采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

 

1、单个组件中的状态

看一下官网提供的计数示例:

<template><div><button class="btn btn-success" @click="increment">increment</button>
      view: {{count}}</div>
</template><script>export default {// state
        data () {return {count: 0}},// actions
        methods: {increment () {this.count++}}}
</script>

运行结果:

从效果图中可以直观的看到,每点击一次按钮触发添加事件(actions),数据count(state)就会发生改变,然后映射到视图界面(view)中。

下图可以表示 “ 单项数据流 ” 理念的极简示意:

这个状态管理应用包含以下几个部分:

• state:驱动应用的数据源

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

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

 

2、多个组件中的状态

当我们的应用遇到 多个组件共享状态 时,单向数据流的简洁性很容易被破坏:

• 多个视图依赖于同一状态

• 来自不同视图的行为需要变更同一状态

 

同样是计数器,我们现在更换一种场景,两个相同的组件A和B,共享一个数据count,并且都有一个方法可以操作这个count(是不是跟上面提到的多组件共享状态描述的一样呢)

// 组件A
<template><div>{{ $store.state.count }}<button @click="increment">组件A</button></div>
</template><script>export default {methods: {increment () {this.$store.commit('increment')}}}
</script>//组件B
<template><div>{{ $store.state.count }}<button @click="increment">组件B</button></div>
</template><script>export default {methods: {increment () {this.$store.commit('increment')}}}
</script>

运行效果:

从图中可以看到,“组件A” 和 “组件B” 两个按钮 会同时改变两个 count 的数据,因为数据源 count 和 方法increment 都是全局的。如下图所示,我们把 全局数据源 state改变数据源的方法 mutations异步操作方法 actions 提取出来放到 store 中,实现全局数据状态单独管理的功能

安装 

1、使用 npm 安装并保存到 package.json 中

npm install vuex --save

package.json

"dependencies": {...,...,...,"vuex": "^2.4.1"},

 

2、配置

// 如果在模块化构建系统中,请确保在开头调用了 Vue.use(Vuex)
import Vue from 'vue'
import Vuex from 'vuex'Vue.use(Vuex)//创建Store实例
const store = new Vuex.Store({// 存储状态值
  state: {...},// 状态值的改变方法,操作状态值// 提交mutations是更改Vuex状态的唯一方法
  mutations: {...},// 在store中定义getters(可以认为是store的计算属性)。Getters接收state作为其第一个函数
  getters: {...},actions: { ...}
})
// 要改变状态值只能通过提交mutations来完成/* eslint-disable no-new */
const app = new Vue({router,i18n,// 将 store 实例注入到根组件下的所有子组件中,子组件通过 this.$store 来访问store
    store,...App
})app.$mount('#app')

看一下官网提供的例子:

<template><div><p>{{ count }}</p><p><button @click="increment">+</button><button @click="decrement">-</button></p></div>
</template><script>export default {computed: {count () {// 通过 store.state 来获取状态对象return this.$store.state.count}},methods: {increment () {// 通过 store.commit 方法触发状态变更this.$store.commit('increment')},decrement () {this.$store.commit('decrement')}}}
</script>
// 创建 Store 实例
const store = new Vuex.Store({// 存储状态值
    state: {count: 0},// 状态值的改变方法,操作状态值// 提交 mutations 是更改Vuex状态的唯一方法
    mutations: {increment: state => state.count++,decrement: state => state.count--}
})

运行效果:

 

核心概念

1、State

state 就是全局的状态(数据源),从前面的例子中看到我们可以按如下方式获取 Vuex 的state 状态

// html 中
{{ $store.state.count }}// js 中
this.$store.state.count

 

2、Getter

getter 可以认为是 store 的计算属性,跟计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会重新计算

如下官网提供的案例:

computed: {doneTodosCount () {return this.$store.state.todos.filter(todo => todo.done).length}
}

如果有多个组件需要用到此属性,我们要么复制这个函数,或者抽取到一个共享函数然后在多处导入它,然而这两种方法都不是很理想,最佳方式当然是使用 getter 了

我们尝试使用下getter

(1)、定义 getter

const store = new Vuex.Store({state: {count: 0},getters: {formatMoney: state => {return '¥'+state.count.toFixed(2)+'元'}},mutations: {increment: state => state.count++}
})

(2)、在组件中引用 getter

export default {methods: {increment () {this.$store.commit('increment')// 这里为了更清楚的看到计算后的值let aaa = document.getElementById('aaa')let p = document.createElement('p')p.innerHTML = this.$store.getters.formatMoneyaaa.appendChild(p)}},computed: {formatMoney() {return this.$store.getters.formatMoney}}}

效果:

3、Mutation

更改 Vuex 的 store 中的状态的唯一方法就是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型(type)和一个 回调函数(handler),这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:

const store = new Vuex.Store({state: {count: 1},mutations: {increment (state) {// 变更状态state.count++}}
})

要唤醒一个 mutation handler,你需要以相应的 type 调用 store.commit 方法

store.commit('increment')

 

(1)、提交载荷(Payload)

载荷(payload)就是说 可以向 store.commit 传入额外的参数

// ...
mutations: {increment (state, n) {state.count += n}
}
store.commit('increment', 10)

在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的mutation会更易读:

// ...
mutations: {increment (state, payload) {state.count += payload.amount}
}
store.commit('increment', {amount: 10
})

 

4、Action

Vuex 中一条重要的原则就是 mutation 必须是同步函数, action 类似于 mutation,不同之处在于:

• Action 提交的是 mutation,而不是直接变更状态

• Action 可以包含任意异步操作

const store = new Vuex.Store({state: {count: 0},mutations: {increment (state) {state.count++}},actions: {increment (context) {context.commit('increment')},// 异步
    incrementAsync (context) {// 延时1秒setTimeout(() => {context.commit('increment')}, 1000)}} 
})

Action 函数接受一个与 store 实例具有相同方法和属性的context对象,因此,可以有以下调用方法

• context.commit  提交一个 mutation

• context.state  获取 state

• context.getters   获取 getters

不同于 mutation 使用 commit 方法,action 使用 dispatch 方法

store.dispatch('increment')

Actions 同样支持 载荷方式 和 对象方式 进行分发:

// 以载荷形式分发
store.dispatch('incrementAsync', {amount: 10
})// 以对象形式分发
store.dispatch({type: 'incrementAsync',amount: 10
})

 

5、Module

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

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

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

 

关于项目结构,我们可以看看官网提供的示例:

├── index.html
├── main.js
├── api
│   └── ... # 抽取出API请求
├── components
│   ├── App.vue
│   └── ...
└── store├── index.js          # 我们组装模块并导出 store 的地方├── actions.js        # 根级别的 action├── mutations.js      # 根级别的 mutation└── modules├── cart.js       # 购物车模块└── products.js   # 产品模块

官网同时也提供了一个 购物车 示例:

app.js 文件如下:

import 'babel-polyfill'
import Vue from 'vue'
import App from './components/App.vue'
import store from './store'
import { currency } from './currency'Vue.filter('currency', currency)new Vue({el: '#app',store,render: h => h(App)
})

index.js 文件如下:

import Vue from 'vue'
import Vuex from 'vuex'
import * as actions from './actions'
import * as getters from './getters'
import cart from './modules/cart'
import products from './modules/products'
import createLogger from '../../../src/plugins/logger'Vue.use(Vuex)const debug = process.env.NODE_ENV !== 'production'export default new Vuex.Store({actions,getters,modules: {cart,products},strict: debug,plugins: debug ? [createLogger()] : []
})

getters.js 文件如下:

export const cartProducts = state => {return state.cart.added.map(({ id, quantity }) => {const product = state.products.all.find(p => p.id === id)return {title: product.title,price: product.price,quantity}})
}

actions.js 文件如下:

import * as types from './mutation-types'export const addToCart = ({ commit }, product) => {if (product.inventory > 0) {commit(types.ADD_TO_CART, {id: product.id})}
}

mutation-type.js 文件如下:

export const ADD_TO_CART = 'ADD_TO_CART'
export const CHECKOUT_REQUEST = 'CHECKOUT_REQUEST'
export const CHECKOUT_SUCCESS = 'CHECKOUT_SUCCESS'
export const CHECKOUT_FAILURE = 'CHECKOUT_FAILURE'
export const RECEIVE_PRODUCTS = 'RECEIVE_PRODUCTS'

cart.js 文件如下:

import shop from '../../api/shop'
import * as types from '../mutation-types'// initial state
// shape: [{ id, quantity }]
const state = {added: [],checkoutStatus: null
}// getters
const getters = {checkoutStatus: state => state.checkoutStatus
}// actions
const actions = {checkout ({ commit, state }, products) {const savedCartItems = [...state.added]commit(types.CHECKOUT_REQUEST)shop.buyProducts(products,() => commit(types.CHECKOUT_SUCCESS),() => commit(types.CHECKOUT_FAILURE, { savedCartItems }))}
}// mutations
const mutations = {[types.ADD_TO_CART] (state, { id }) {state.lastCheckout = nullconst record = state.added.find(p => p.id === id)if (!record) {state.added.push({id,quantity: 1})} else {record.quantity++}},[types.CHECKOUT_REQUEST] (state) {// clear cartstate.added = []state.checkoutStatus = null},[types.CHECKOUT_SUCCESS] (state) {state.checkoutStatus = 'successful'},[types.CHECKOUT_FAILURE] (state, { savedCartItems }) {// rollback to the cart saved before sending the requeststate.added = savedCartItemsstate.checkoutStatus = 'failed'}
}export default {state,getters,actions,mutations
}

products.js 文件如下:

import shop from '../../api/shop'
import * as types from '../mutation-types'// initial state
const state = {all: []
}// getters
const getters = {allProducts: state => state.all
}// actions
const actions = {getAllProducts ({ commit }) {shop.getProducts(products => {commit(types.RECEIVE_PRODUCTS, { products })})}
}// mutations
const mutations = {[types.RECEIVE_PRODUCTS] (state, { products }) {state.all = products},[types.ADD_TO_CART] (state, { id }) {state.all.find(p => p.id === id).inventory--}
}export default {state,getters,actions,mutations
}

购物车运行效果:

转载于:https://www.cnblogs.com/rogerwu/p/7606156.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/280241.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

xdf文档怎么转换为pdf_如何将PDF文件和图像转换为Google文档文档

xdf文档怎么转换为pdfYou probably know you can create and edit documents with Google Docs, but you can edit more than just .doc files. Google Drive can also convert any PDF, JPG, PNG, or GIF into a document with fully editable text. Here’s how. 您可能知道可…

在现代 Windows 上使用经典 Windows 2000、XP、Vista 任务栏

你好&#xff0c;这里是 Dotnet 工具箱&#xff0c;定期分享 Dotnet 有趣&#xff0c;实用的工具和组件&#xff0c;希望对您有用&#xff01;前言您第一次使用的 Windows 是哪个版本的&#xff1f;我最早使用的 Windows XP&#xff0c;然后再经过 XP、7、8/8.1 、Windows 10&a…

airdroid黑屏_如何使用AirDroid从PC控制Android设备

airdroid黑屏AirDroid for Android replaces your USB cable for connecting to your PC. Transfer files back and forth, send text messages, play music, view your photos, and manage applications using a web browser or a desktop client. 适用于Android的AirDroid取代…

分析java程序

2019独角兽企业重金招聘Python工程师标准>>> 最近公司的一个账单推送的服务&#xff0c;发现有延迟。我排查的时候发现&#xff0c;有一个程序日志不动了&#xff08;采用消息队列&#xff0c;部署了两台服务器来负载均衡&#xff09;。 网上说&#xff1a; jstack …

环境部署(九):linux下安装python+chrome+Xvfb

在基于selenium进行的UI自动化测试中&#xff0c;开发调试环境一般都是windows操作系统。完成后需要部署到专门的测试环境。 如要要部署到linux环境的服务器&#xff08;阿里云、腾讯云&#xff09;执行&#xff0c;那么测试脚本也需要对应的浏览器支持&#xff0c; 才能正常进…

地理围栏_什么是“地理围栏”?

地理围栏The term is popping up more frequently in news articles, appearing in product manuals, and highlighted as a feature in tons of mobile applications, but what exactly is geofencing? Read on as we explain what it is, why it’s appearing in more produ…

嵌套映射

1. 多对一嵌套查询映射使用案例 package com.zixue.dao;import com.zixue.annotation.MyBatisRepository; import com.zixue.entity.Emp;/*** 员工表的DAO组件* */ MyBatisRepository public interface EmpDao {void save(Emp emp);Emp findById(int id);Emp findById2(int id)…

gopro dataset_如何将GoPro安装到DSLR相机

gopro datasetIf you have a DSLR camera with a hot shoe, it’s easy to attach various flashes and other accessories right to your camera. But with a couple of cheap attachments on hand, you can mount your GoPro to your DSLR camera as well. 如果您的DSLR相机带…

jQuery已经过时了,还需要学吗?

说起jQuery&#xff0c;很多刚参加工作的程序员都没用过&#xff0c;甚至没听过。曾几何时jQuery可是秒杀一切Js库&#xff0c;大有一统江山的情况&#xff0c;可是在顶峰的时候&#xff0c;瞬间被Vue、React、Angela三大框架斩于马下。从百度指数&#xff0c;我们也看出在2015…

Bootstrap01

Bootstrap01内容概要 一.使用Bootstrap的步骤 1.下载Bootstrap类库,包含三个部分,fonts,css,Bootstrap 2.导入项目中,在头部引入JQ,css和Bootstrap 注意:JQ要引入在Bootstrap前面! 3.使用css样式时,全部使用class属性 二.全局CSS概要 1.仅支持H5文档格式 2.移动设备优先,需要在…

ios raise_如何在iOS 10中关闭“ Raise to Wake”

ios raiseRaise to Wake is a new Lock screen feature available in iOS 10. It allows you to wake your phone’s screen simply by picking up your phone. This feature is on by default, but if you’d rather not use it, it’s simple to turn off. “唤醒”是iOS 10中…

资源调度器调研

2019独角兽企业重金招聘Python工程师标准>>> 场景描述&#xff1a; 异步触发和Crontab触发 YARN(Yet Another Resource Negotiator)Hadoop 资源管理器 主要构成&#xff1a; RM(ResourceManager)是一个全局的资源管理器&#xff0c;负责整个系统的资源管理和分配。…

WPF-19 IValueConverter接口

我们先来看看微软官方给出的定语&#xff1a;提供将自定义逻辑应用于绑定的方法&#xff0c;我们来看一下该接口的定义&#xff0c;Convert提供了将数据源到UI的格式化&#xff0c;ConvertBack表示反向namespace System.Windows.Data {//// Summary:// Provides a way to a…

使用 Azure CLI 将 IaaS 资源从经典部署模型迁移到 Azure Resource Manager 部署模型

以下步骤演示如何使用 Azure 命令行接口 (CLI) 命令将基础结构即服务 (IaaS) 资源从经典部署模型迁移到 Azure Resource Manager 部署模型。 本文中的操作需要 Azure CLI。 Note 此处描述的所有操作都是幂等的。 如果你遇到功能不受支持或配置错误以外的问题&#xff0c;建议你…

黑苹果不能imessage_如何修复iMessage在iOS 10中不显示消息效果

黑苹果不能imessageiMessage got a huge update in iOS 10, adding things like third-party app integration, rich links, and a number of fun graphical effects for messages. If you’re seeing messages that say something like “(sent with Invisible Ink)” instead…

从技术总监到开源社区运营:过去两年,我都做了点啥?

这是头哥侃码的第267篇原创今天&#xff0c;这是我离开前公司的第 7 天。相信有不少吃瓜群众都很好奇&#xff0c;你这些天都在干啥&#xff1f;是不是蓬莱乐逍遥&#xff0c;过上了那悠闲的神仙日子&#xff1f;还是趁着疫情管控逐渐放开&#xff0c;和家人一起去深山老林里吸…

查看模拟器使用端口_为什么我们仍然使用模拟音频端口?

查看模拟器使用端口When leaks about what the chassis of the iPhone 7 might look like hit headlines earlier this week, technology columnists and industry analysts jumped on the chance to report that Apple’s next device may finally ditch its 3.5mm audio port…

如何更改Windows 10锁定屏幕超时

By default, Windows 10’s lock screen times out and switches off your monitor after one minute. If you’d like it to stick around longer than that–say, if you have background picture you like looking at or you enjoy having Cortana handy–there’s a simple…

ios 开发账号 退出协作_如何在iOS 10中的Notes上进行协作

ios 开发账号 退出协作iOS’ Notes app provides a convenient way to remember the great ideas you come up with and all the things you have to do. The app has evolved over the years, and iOS 10 adds even more features–including collaboration. iOS的Notes应用程…

为什么Android Geeks购买Nexus设备

The Galaxy S III is the highest-selling Android phone, but much of the geeky buzz is around the Nexus 4 – and the Galaxy Nexus before it. Nexus devices are special because they don’t have some of Android’s biggest problems. Galaxy S III是最畅销的Android…