vuejs2.0 Vuex 实际应用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kingrome2017/article/details/82253060

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 store 模式就足够您所需了。但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。

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)
    )
  }
}

以下是官方实例--购物车

vuex

/**
 * 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 模式

vuex


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

猜你喜欢

转载自blog.csdn.net/kingrome2017/article/details/82253060