vuejs2.0 Vuex 实际应用
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 store 模式就足够您所需了。但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。
简单的 store 模式
//html
<div id="app">
<p>{{ count }}</p>
<p>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</p>
</div>
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment: state => state.count++,
decrement: state => state.count--
}
})
//js
new Vue({
el: '#app',
computed: {
count () {
return store.state.count
}
},
methods: {
increment () {
store.commit('increment')
},
decrement () {
store.commit('decrement')
}
}
当时做了一个全部展开、收起的功能,是一个树结构,操作杆在父组件,事件在子组件,为了能同步采用了简单的写法,但是后来优化了代码,通过给data追加属性和值动态响应,也解决了这个问题,很符合vue数据处理的初衷
容易的 store 模式
这一块先从官方文档说起state里面有一个mapState,返回一个对象,getter相当于store里的计算属性接受state作为参数,mapGetters 辅助函数使用对象展开运算符将 getter 混入 computed 对象中,更改 Vuex 的 store 中的状态的唯一方法是提交 mutation,关于Action 提交的是 mutation,而不是直接变更状态,支持异步操作
export default {
// ...
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
//官方实例购物的部分代码
actions: {
checkout ({ commit, state }, products) {
// 把当前购物车的物品备份起来
const savedCartItems = [...state.cart.added]
// 发出结账请求,然后乐观地清空购物车
commit(types.CHECKOUT_REQUEST)
// 购物 API 接受一个成功回调和一个失败回调
shop.buyProducts(
products,
// 成功操作
() => commit(types.CHECKOUT_SUCCESS),
// 失败操作
() => commit(types.CHECKOUT_FAILURE, savedCartItems)
)
}
}
以下是官方实例--购物车
/**
* shop.js
*/
const _products = [
{"id": 1, "title": "iPad 4 Mini", "price": 500.01, "inventory": 2},
{"id": 2, "title": "H&M T-Shirt White", "price": 10.99, "inventory": 10},
{"id": 3, "title": "Charli XCX - Sucker CD", "price": 19.99, "inventory": 5}
]
export default {
getProducts (cb) {
setTimeout(() => cb(_products), 100)
},
buyProducts (products, cb, errorCb) {
setTimeout(() => {
// simulate random checkout failure.
(Math.random() > 0.5 || navigator.userAgent.indexOf('PhantomJS') > -1)
? cb()
: errorCb()
}, 100)
}
}
shop.js里面定义了一组mock数据,还有两个方法,支持回调函数
/**
* store--index.js
*/
import Vue from 'vue'
import Vuex from 'vuex'
import cart from './modules/cart'
import products from './modules/products'
Vue.use(Vuex)
//在dev模式下开启debug严格模式
const debug = process.env.NODE_ENV !== 'production'
export default new Vuex.Store({
modules: {
cart,
products
},
strict: debug,
})
下面是productlist页面和store里面的product.js,创建实例后请求接口生成页面,用到命名空间直接调取cart.js里方法
<template>
<ul>
<li v-for="product in products">
{{ product.title }} - {{ product.price | currency }}
<br>
<button
:disabled="!product.inventory"
@click="addProductToCart(product)">
Add to cart
</button>
</li>
</ul>
</template>
<script>
import { mapState, mapActions } from 'vuex'
export default {
computed: mapState({
products: state => state.products.all
}),
methods: mapActions('cart', [
'addProductToCart'
]),
created () {
this.$store.dispatch('products/getAllProducts')
}
}
</script>
/**
* store--product.js
*/
import shop from '../../api/shop'
// initial state
const state = {
all: []
}
// getters
const getters = {}
// actions
const actions = {
getAllProducts ({ commit }) {
shop.getProducts(products => {
commit('setProducts', products)
})
}
}
// mutations
const mutations = {
setProducts (state, products) {
state.all = products
},
decrementProductInventory (state, { id }) {
const product = state.all.find(product => product.id === id)
product.inventory--
}
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
/**
* store--cart.js
*/
import shop from '../../api/shop'
// initial state
// shape: [{ id, quantity }]
const state = {
items: [],
checkoutStatus: null
}
// getters
const getters = {
cartProducts: (state, getters, rootState) => {
return state.items.map(({ id, quantity }) => {
const product = rootState.products.all.find(product => product.id === id)
return {
title: product.title,
price: product.price,
quantity
}
})
},
cartTotalPrice: (state, getters) => {
return getters.cartProducts.reduce((total, product) => {
return total + product.price * product.quantity
}, 0)
}
}
// 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 })
}
)
},
addProductToCart ({ state, commit }, product) {
commit('setCheckoutStatus', null)
if (product.inventory > 0) {
const cartItem = state.items.find(item => item.id === product.id)
if (!cartItem) {
commit('pushProductToCart', { id: product.id })
} else {
commit('incrementItemQuantity', cartItem)
}
// remove 1 item from stock
commit('products/decrementProductInventory', { id: product.id }, { root: true })
}
}
}
// 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
}
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
应用级的 store 模式
import Vue from 'vue'
import Vuex from 'vuex'
import actions from './actions'
import *as getters from './getters'
import state from './state'
import mutations from './mutation'
Vue.use(Vuex)
export default new Vuex.Store({
actions,
getters,
state,
mutations
})
getters.js
import state from "./state";
export const psnumber = state => state.psd_VipNumber
export const storeToken = state => state.store_token
export const number = state => state.number
export const shopCarCount = state => state.shopCarCount
export const loading = state => state.loading
mutation.js
import *as types from './mutation-types'
const mutations = {
[types.PSD_NUMBER] (state, psd_Number){
state.psd_VipNumber = psd_Number
},
[types.STORE_TOKEN] (state, store_token){
state.store_token = store_token
},
[types.PHONE_NUMBER] (state, phoneNumber){
state.number = phoneNumber
},
[types.LOADINGSHOW] (state){
state.loading = true
},
[types.LOADINGHIDE] (state){
state.loading = false
},
}
export default mutations
state.js
const state = {
psd_VipNumber: {},
store_token: {},
number: {},
shopCarCount:0,
loading:false
}
export default state
mutation-types.js,为了规范代码,后期好维护,其实vuex是很简单的,切记一点不要刻意的使用它,好多事情,其实可以和数据挂钩,既然vue是数据驱动的,改变数据能做到的就不要用vuex,毕竟它也是一个全局的概念
/*这里是定义常亮类型的*/
export const PSD_NUMBER = 'PSD_NUMBER'
export const STORE_TOKEN = 'STORE_TOKEN'
export const PHONE_NUMBER = 'PHONE_NUMBER'
export const LOADINGSHOW = 'LOADINGSHOW'
export const LOADINGHIDE = 'LOADINGHIDE'
当然如何去修改state,下面将做一个简单的说明,更多内容到我的另一篇博客有更多介绍
vuejs2.0 高级实战 全网稀缺
methods: {
random() {
this.randomPlay({
list: this.songs
})
},
...mapActions([
'selectPlay',
'randomPlay'
])
},
//actions.js
export const randomPlay = function ({commit}, {list}) {
commit(types.SET_PLAY_MODE, playMode.random)
commit(types.SET_SEQUENCE_LIST, list)
let randomList = shuffle(list)
commit(types.SET_PLAYLIST, randomList)
commit(types.SET_CURRENT_INDEX, 0)
commit(types.SET_FULL_SCREEN, true)
commit(types.SET_PLAYING_STATE, true)
}
在methods里面通过语法糖引入方法的映射传入一个list,通过参入的list操作其他commit-mutions
上一篇: Java 判断奇偶的小细节