欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

vuejs2.0 Vuex 实际应用

程序员文章站 2022-04-02 18:12:54
...

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

vuejs2.0 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)
    )
  }
}

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

vuejs2.0 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 模式

vuejs2.0 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

相关标签: vuex