目錄:
- 核心概念使用方法及場(chǎng)景:
- state
- mutations
- actions
- getters
- 多頁(yè)面公用vuex實(shí)例
- 在頁(yè)面中調(diào)用后端接口展示數(shù)據(jù)案例
參考鏈接:
vuex簡(jiǎn)介
vue.js的狀態(tài)管理vuex中store的使用
理解vuex侦啸,看這篇就夠了
本文中不再詳細(xì)介紹vuex基本概念和用法,若想詳細(xì)了解請(qǐng)參考第一鏈接锐峭!
1. 核心核心概念使用方法及場(chǎng)景:
1.1 state
單一狀態(tài)管理樹窒舟,只有在這里聲明我們需要的數(shù)據(jù)類型和值写半,才能在vue組件中獲取定義的對(duì)象的狀態(tài)屿衅。
1.2 mutations
mutations翻譯是更改畅卓,更改store中state中的狀態(tài)值的唯一方法就是提交mutations,每一個(gè)mutations都有一個(gè)字符串類型的事件類型和回調(diào)函數(shù)擅腰,執(zhí)行這個(gè)回調(diào)調(diào)函的方法有三個(gè),本質(zhì)上是一個(gè):提交mutations,即commit mutations,提交時(shí)附加一些payload數(shù)據(jù)翁潘,叫做負(fù)荷趁冈。
- 基本用法:
mutations:{
increment(state,payload){
state.count = payload.number //這里改變state中的數(shù)據(jù)
}
}
① 在actions中commit(回調(diào)函數(shù)名,payload)拜马,具體使用情況看下面的案例.
② 在組件中methods里this.$store.commit(回調(diào)函數(shù)名渗勘,payload).
③ 在組件中使用mapMutations輔助函數(shù)將組件中的mutatios映射為this.$store.commit("回調(diào)函數(shù)名",{傳入的第二個(gè)}).
1.3 actions
- 1.3.1 actions基本用法:
actions很多地方都和mutations用法類似俩莽,最大的不同就是actions可以是異步函數(shù)旺坠,但mutations必須是同步函數(shù),而且actions不能直接修改state,是通過commit mutations(上一內(nèi)容)來改變state.聲明actions時(shí)它接受的第一個(gè)參數(shù)就是和state有相同方法和屬性的context對(duì)象扮超,第二個(gè)參數(shù)也是payload取刃。觸發(fā)actions的方法:
① 在actions通過context.commit(mutations中回調(diào)函數(shù)名,payload)
② 在組件中methods里分發(fā):this.$store.dispatch("mutations中回調(diào)函數(shù)名"出刷,{payload})
③ 使用 mapActions輔助函數(shù)璧疗,將組件中的methods映射為this.$store.dispatch調(diào)用
export default{
methods:{
...mapActions([
'mutations的回調(diào)函數(shù)名'
])
},
/* ----------或者-----------*/
...mapActions({
頁(yè)面展示用的名稱 : 'mutations的回調(diào)函數(shù)名'
})
}
- 1.3.2 actions嵌套用法:
actions中可以是異步函數(shù),這就使得actions中可以嵌套另外一個(gè)actions馁龟,即this.$store.dispatch()可以處理已經(jīng)被觸發(fā)得的actions得到的promise,處理后的結(jié)果仍返回promise對(duì)象崩侠。
//組合性的異步嵌套actions的操作
actions:{
actionA({commit}){
return new Promise((resolve,reject) =>{
setTimeout(() => {
commit('someMutation') //會(huì)把得到的數(shù)據(jù)保存到someMutation位置
} ,10000)
})
}
}
//在某一個(gè)頁(yè)面組件中觸發(fā):
this.$store.dispatch("actionA").then(() => {
//...
})
//在另外一個(gè)actions中也可以這樣寫,actionB處理actionA被觸發(fā)得到的Promise,再提交someOtherMutations
actions:{
//...
actionB({diapatch,commit}){
return dispatch('actionA').then(
commit('someOtherMutations')
)
}
}
- 再結(jié)合async await 優(yōu)化組合actions的代碼
actions : {
async actionA({commit} {
commit('gotData',await getData())
}),
async actionB({dispatch,commit}){
await dispatch('actionA') //等待actionA執(zhí)行完成后再執(zhí)行
commit('gotOtherData', await getOtherData)
}
}
1.4 getters
getter類似于Vue.js 的computed計(jì)算屬性屁柏,當(dāng)我們需要從state中派生一些狀態(tài)就用getter函數(shù)啦膜,getter函數(shù)的第一個(gè)參數(shù)為state,還可以接受其他參數(shù)有送,而且它的返回值被緩存起來,只有當(dāng)getter依賴值(state中的相關(guān)狀態(tài)值)發(fā)生改變才會(huì)被重新計(jì)算僧家。
- 基本用法:
getters:{
doneTodos : {
return state.todosfilter(todo => todos.count)
}
}
- 在頁(yè)面中觸發(fā)getters的兩種方法:
- 可以通過this.$store.getters.doneTodos方法可以訪問得到這些派生出來的狀態(tài)值
- 還可以使用輔助函數(shù):
export default{ computed : { //當(dāng)同時(shí)使用多個(gè)getter函數(shù)時(shí)可以這樣寫 ...mapGetters([ 'doneTodos', 'anotherGetters' ]) } }
- 如果想給一個(gè)getters(doneTodos)再取一個(gè)名字,則使用對(duì)象形式
export default{
computed : {
...mapGetters({
anotherName: 'doneTodos'
})
}
}
1.5 mudules
當(dāng)store太過于復(fù)雜的時(shí)候?qū)λ囊环N切割雀摘,每一個(gè)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的狀態(tài)
store.state.b // moduleB的狀態(tài)
1.6 mudules局部狀態(tài)
- 模塊內(nèi)部mutations 和getters
對(duì)于模塊內(nèi)部的mutation和getter接受的第一個(gè)參數(shù)就是模塊內(nèi)部局部狀態(tài)對(duì)象
- 模塊內(nèi)部mutations 和getters
moduleA = {
// ...
state:{count:0},
mutation : {
increment(state){
// 這里的state就是模塊的局部狀態(tài)
state.count ++
}
},
getters : {
doubleCount(state){
// 這里的state就是模塊的局部狀態(tài)
return state.count * 2
}
}
}
- 模塊內(nèi)部actions
對(duì)于模塊內(nèi)部的actions,模塊內(nèi)部局部狀態(tài)會(huì)通過 context.state方式暴露出來
- 模塊內(nèi)部actions
moduleA = {
// ...
actions : {
increment({state,context}){
if(context.state.count % 2 === 1){
context.commit('increment')
}
}
}
}
- 根節(jié)點(diǎn)
對(duì)于模塊內(nèi)部的getters和actions根節(jié)點(diǎn)的暴露方式:
- 根節(jié)點(diǎn)
moduleA = {
// ...
//跟節(jié)點(diǎn)會(huì)通過第三個(gè)參數(shù)暴露出來
getters : {
sumWithRootCount(state,context,rootState ){
return state.count + rooState.count
}
},
//根節(jié)點(diǎn)狀態(tài)會(huì)通過context.rootState暴露出來
actions : {
incrementRootSum(state,context,rootState){
if(context.rootState.count % 2 === 1){
context.commit('incrementRootSum')
}
}
}
}
1.7 vuex — 計(jì)算屬性 — 實(shí)現(xiàn)雙向綁定,使用帶有setter的計(jì)算屬性
假設(shè)obj是計(jì)算屬性返回的屬于vuex store中的一個(gè)對(duì)象
<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. 移動(dòng)端多頁(yè)面公用vuex案例
2.1 情景介紹:
當(dāng)前端開發(fā)調(diào)用后端接口獲取數(shù)據(jù)八拱,并在多個(gè)頁(yè)面中展示數(shù)據(jù)時(shí)阵赠,任意組件之間通信,最好的方法就是使用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
}
})
- 創(chuàng)建兩個(gè)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>