目录:
- 核心概念使用方法及场景:
- state
- mutations
- actions
- getters
- 多页面公用vuex实例
- 在页面中调用后端接口展示数据案例
参考链接:
vuex简介
vue.js的状态管理vuex中store的使用
理解vuex,看这篇就够了
本文中不再详细介绍vuex基本概念和用法,若想详细了解请参考第一链接!
1. 核心核心概念使用方法及场景:
1.1 state
单一状态管理树,只有在这里声明我们需要的数据类型和值,才能在vue组件中获取定义的对象的状态。
1.2 mutations
mutations翻译是更改,更改store中state中的状态值的唯一方法就是提交mutations,每一个mutations都有一个字符串类型的事件类型和回调函数,执行这个回调调函的方法有三个,本质上是一个:提交mutations,即commit mutations,提交时附加一些payload数据,叫做负荷。
- 基本用法:
mutations:{
increment(state,payload){
state.count = payload.number //这里改变state中的数据
}
}
① 在actions中commit(回调函数名,payload),具体使用情况看下面的案例.
② 在组件中methods里this.$store.commit(回调函数名,payload).
③ 在组件中使用mapMutations辅助函数将组件中的mutatios映射为this.$store.commit("回调函数名",{传入的第二个}).
1.3 actions
- 1.3.1 actions基本用法:
actions很多地方都和mutations用法类似,最大的不同就是actions可以是异步函数,但mutations必须是同步函数,而且actions不能直接修改state,是通过commit mutations(上一内容)来改变state.声明actions时它接受的第一个参数就是和state有相同方法和属性的context对象,第二个参数也是payload。触发actions的方法:
① 在actions通过context.commit(mutations中回调函数名,payload)
② 在组件中methods里分发:this.$store.dispatch("mutations中回调函数名",{payload})
③ 使用 mapActions辅助函数,将组件中的methods映射为this.$store.dispatch调用
export default{
methods:{
...mapActions([
'mutations的回调函数名'
])
},
/* ----------或者-----------*/
...mapActions({
页面展示用的名称 : 'mutations的回调函数名'
})
}
- 1.3.2 actions嵌套用法:
actions中可以是异步函数,这就使得actions中可以嵌套另外一个actions,即this.$store.dispatch()可以处理已经被触发得的actions得到的promise,处理后的结果仍返回promise对象。
//组合性的异步嵌套actions的操作
actions:{
actionA({commit}){
return new Promise((resolve,reject) =>{
setTimeout(() => {
commit('someMutation') //会把得到的数据保存到someMutation位置
} ,10000)
})
}
}
//在某一个页面组件中触发:
this.$store.dispatch("actionA").then(() => {
//...
})
//在另外一个actions中也可以这样写,actionB处理actionA被触发得到的Promise,再提交someOtherMutations
actions:{
//...
actionB({diapatch,commit}){
return dispatch('actionA').then(
commit('someOtherMutations')
)
}
}
- 再结合async await 优化组合actions的代码
actions : {
async actionA({commit} {
commit('gotData',await getData())
}),
async actionB({dispatch,commit}){
await dispatch('actionA') //等待actionA执行完成后再执行
commit('gotOtherData', await getOtherData)
}
}
1.4 getters
getter类似于Vue.js 的computed计算属性,当我们需要从state中派生一些状态就用getter函数,getter函数的第一个参数为state,还可以接受其他参数,而且它的返回值被缓存起来,只有当getter依赖值(state中的相关状态值)发生改变才会被重新计算。
- 基本用法:
getters:{
doneTodos : {
return state.todosfilter(todo => todos.count)
}
}
- 在页面中触发getters的两种方法:
- 可以通过this.$store.getters.doneTodos方法可以访问得到这些派生出来的状态值
- 还可以使用辅助函数:
export default{ computed : { //当同时使用多个getter函数时可以这样写 ...mapGetters([ 'doneTodos', 'anotherGetters' ]) } }
- 如果想给一个getters(doneTodos)再取一个名字,则使用对象形式
export default{
computed : {
...mapGetters({
anotherName: 'doneTodos'
})
}
}
1.5 mudules
当store太过于复杂的时候对它的一种切割,每一个module都有自己的state,mutation,action和getter
moduleA = {
state:{},
mutations:{},
actions:{},
getters:{}
},
moduleB = {
state:{},
mutations:{},
actions:{},
getters:{}
},
const store new Vuex.Store({
a : moduleA,
b : moduleB
})
store.state.a // moduleA的状态
store.state.b // moduleB的状态
1.6 mudules局部状态
- 模块内部mutations 和getters
对于模块内部的mutation和getter接受的第一个参数就是模块内部局部状态对象
- 模块内部mutations 和getters
moduleA = {
// ...
state:{count:0},
mutation : {
increment(state){
// 这里的state就是模块的局部状态
state.count ++
}
},
getters : {
doubleCount(state){
// 这里的state就是模块的局部状态
return state.count * 2
}
}
}
- 模块内部actions
对于模块内部的actions,模块内部局部状态会通过 context.state方式暴露出来
- 模块内部actions
moduleA = {
// ...
actions : {
increment({state,context}){
if(context.state.count % 2 === 1){
context.commit('increment')
}
}
}
}
- 根节点
对于模块内部的getters和actions根节点的暴露方式:
- 根节点
moduleA = {
// ...
//跟节点会通过第三个参数暴露出来
getters : {
sumWithRootCount(state,context,rootState ){
return state.count + rooState.count
}
},
//根节点状态会通过context.rootState暴露出来
actions : {
incrementRootSum(state,context,rootState){
if(context.rootState.count % 2 === 1){
context.commit('incrementRootSum')
}
}
}
}
1.7 vuex — 计算属性 — 实现双向绑定,使用带有setter的计算属性
假设obj是计算属性返回的属于vuex store中的一个对象
<input v-model="message">
export default{
//...
computed:{
message : {
get(){
return this.$store.state.obj.message
},
set(value){
this.$store.commit('updateMessage',value)
}
}
}
}
store中的mutaions:
// ...
mutatoins : {
undateMessage(state,message){
state.obj.message = message
}
}
2. 移动端多页面公用vuex案例
2.1 情景介绍:
当前端开发调用后端接口获取数据,并在多个页面中展示数据时,任意组件之间通信,最好的方法就是使用vuex.
2.2 使用方法:使用案例 https://github.com/vuejs/vuex/tree/dev/examples
- 入口文件 : main.js
import Vue from 'vue';
import App from './components/App.vue';
import store from './store';
import { currency } from './currency'
Vue.filter('currency',currency)
var vm = new Vue({
el:'#app',
store,
render : h => h(App)
})
- 定义vuex .store: ./store/index.js中的代码
import Vue from 'vue'
import Vuex from 'vuex'
import cart from './modules/cart'
import products from './modules/products'
import createLogger from '../../../src/plugins/logger'
Vue.use(Vuex)
export default new Vuex.store({
modules:{
cart,
products
}
})
- 创建两个module:
- ./store/modules/cart.js
import shop from '../../api/shop'
//初始化state
const state = () => {
items : [ ],
checkoutStatus : null
}
//getters
const getters = {
cartProducts : (state,getters,rootState) =>{
return state.item.map({id,quantity}) => {
const product = rootState.prosucts.all.find(product => product.id === id)
return {
title : products.title,
price : products.price,
quantity
}
}
},
cartTotalProducts : (state,getters)=>{
return getters.cartProducts.reduce((products,total)=>{
return total = products.price * products.quantity
},0)
}
}
//mutations
const mutations = {
pushProductToCart(state,{id}){
state.items.push({
id,
quantity : 1
})
} ,
incrementItemQuantity (state, { id }) {
const cartItem = state.items.find(item => item.id === id)
cartItem.quantity++
},
setCartItems (state, { items }) {
state.items = items
},
setCheckoutStatus (state, status) {
state.checkoutStatus = status
}
}
//actions
const actions = {
checkout ({ commit, state }, products) {
const savedCartItems = [...state.items]
commit('setCheckoutStatus', null)
// empty cart
commit('setCartItems', { items: [] })
shop.buyProducts(
products,
() => commit('setCheckoutStatus', 'successful'),
() => {
commit('setCheckoutStatus', 'failed')
// rollback to the cart saved before sending the request
commit('setCartItems', { items: savedCartItems })
}
)
}
- ./store/modules/products.js
import shop from '../../api/shop';
//initial state
const state = () => ({
all : []
})
// mutations
const mutations = {
setProductss(state,products){
state.all = products
},
decrementProductInventory(state,{id}){
const product = state.all.find(product => product.id = id)
product.inventory --
}
}
//actions
const actions = {
getAllProducts({commit}){
shop.getProducts(products =>{
commit('setProducts',products)
})
}
}
//getters
const getters = {
}
export default{
namespaced = true,
state,
actions,
mutations,
getters
}
- 通信的组件:
- /component/App.vue
<template>
<div id="app">
<h1>shopping cart example</h1>
<hr>
<h2>products example</h2>
<ProductList/>
<hr>
<h2>cart example</h2>
<ShoppingCart/>
</div>
</template>
<script>
import ProductList from './ProductList.vue';
import ShoppingCart from './Cart.vue';
export deafult{
components:{
ProductList,
ShoppingCart
}
}
</script>
- /component/ProductList.vue
<template>
<ul>
<li v-for="product in products" :key="product.id">
{{product.title}}-{{product.price | currency}}
<button :disabled="product.inventory" @click="addProductToCart(product)">
add to cart
</button>
</li>
</ul>
</template>
<script>
import { mapSate, mapActions } from "vuex"
export default{
// ...
computed : ...mapState({
products: state => state.products.all
}),
methods : ...mapActions('cart',[
'addProductToCart'
]),
created(){
this.$store.dispatch('products/getAllProducts')
}
}
</script>
- /component/ShoppingCart.vue
<template>
<div class="cart">
<h2>Your cart</h2>
<p v-show="!products.length"><i>please add some products to cart.</i></p>
<ul>
<li v-for="product in products" :key="product.id">
{{ product.title }} - {{ product.price | currency }} x {{ product.quantity }}
</li>
</ul>
<p>Total:{{total | currency}}</p>
<p><button :disabled="!product.length" @click="checkout(products)">checkout</button></p>
<p v-show="checkoutStatus">Checkout{{checkoutStatus}}.</p>
</div>
</template>
<script>
import { mapGetters, mapState } from 'vuex';
export default{
computed : {
...mapState){
checkoutStatus : state => state.cart.checkoutStatus
}),
...mapGetters:('cart',{
products : 'cartProducts',
total : 'cartTotalProducts'
})
},
methods : {
checkout(products){
this.$store.dispatch('cart/checkout', products)
}
}
}
</script>