vue学习日记05

vuex

 

例如创建一个min-vuex.js

import Vue from 'vue'
const Store = function Store (options = {}) {
    const {state = {} , mutations ={}} = options
    this._vm = new Vue ({
        data : {
            $$state: state
        }
    })this._mutations = mutations
}
Store.prototype.commit = function (type, payload) {
    if(this._mutations[type]) {
        this._mutations[type](this.state, payload)
    }
}
Object.defineProperties(Store.prototype, {
    state: {
        get: function() {
            return this._vm._data.$$state
        }
    }
})

export default {Store}

import Vue from 'vue'
import App from './App'
import router from './router'
import Vuex from './min-vuex'

Vue.config.productionTip = false

const store = new Vuex.Store({
  state: {
    count : 0
  },
  mutations: {
    increment (state, n) {
      state.count += n
    }
  }
})
/* eslint-disable no-new */
Vue.prototype.$store = store 

new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

https://www.jianshu.com/p/d95a7b8afa06 这篇文章有工作原理解释。

我们在使用vuex的时候,官方还提供了一些辅助函数。如 mapState, mapGetter,mapActions。

mapState:

 假如我们在计算属性中返回state里的值,普通用法就需要返回很多个,用辅助函数就可以缩写,以mapState为例

// 先引入
import { mapState, mapActions } from 'vuex'
 
 
// 普通用法
computed: {     
 products(){
      return this.$store.state.products.all
    }
  },
 
 // mapState 辅助函数用法
  computed: mapState({  
    products: state => state.products.all,
  }),
 
 //如果state的名称与你计算属性名称相同,可以传一个字符串数组
  computed: mapState(['products']),
 
  //如果该组件还存在其他计算属性
  computed: {    
    ...mapState({
      products: state => state.products.all,
    }),
    other() {
      return 'other computed'
    }
  }

其他函数也大致相同,目的就是简化一些 this.$store.state之类的操作。

Module

  官网例子:

  

  由此可见,每个module都有自己单独的state,mutations,actions,getters。

  但是如果,在每个module的mutations或actons中,存在有一样名字的函数,如每个模块中都包含 setName的actions,我们在调用 this.$store.dispatch('setName‘) 的时候,

  所有模块中的同名actions都会被执行。因此若要避免这个情况,我们就需要给每个actions单独命名,或者给每个模块使用上命名空间。

// moduleA.js
const state = {   ...... } // getters const getters = {   ...... } // actions const actions = {   ...... } // mutations const mutations = {   ...... } export default { namespaced: true, state, getters, actions, mutations }

这个时候我们调用的话,就需要加上命名空间的字段 this.$store.dispatch('moduleA/....'),同时mapState等也有的同样的改变。

 computed: {
  ...mapState("moduleA",{
   useName: state => state.useName
  }),
  ...mapGetters("moduleA", ["userName"])
 },

 在使用了命名空间之后,每个模块中的getters会产生第三个参数,rootState作为根数据。数据格式是一个对象,然后每个模块的state都是该对象中的一个属性,值也是一个对象,包含该模块的state数据。

一个具体例子:

目录结构:

//  cart.js
import shop from '../../api/shop' import { CART, PRODUCTS } from '../mutations-types' // 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) console.log(rootState.products.all,'....111.') 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(CART.SET_CHECKOUT_STATUS, null) // empty cart commit(CART.SET_CART_ITEMS, { items: [] }) shop.buyProducts( products, () => commit(CART.SET_CHECKOUT_STATUS, 'successful'), () => { commit(CART.SET_CHECKOUT_STATUS, 'failed') // rollback to the cart saved before sending the request commit(CART.SET_CART_ITEMS, { items: savedCartItems }) } ) }, setName ({state,commit,rootState}) { commit('cartSetName',rootState.userInfo) }, addProductToCart ({ state, commit }, product) { commit(CART.SET_CHECKOUT_STATUS, null) if (product.inventory > 0) { const cartItem = state.items.find(item => item.id === product.id) if (!cartItem) { commit(CART.PUSH_PRODUCT_TO_CART, { id: product.id }) } else { commit(CART.INCREMENT_ITEM_QUANTITY, cartItem) } // remove 1 item from stock commit(`products/${PRODUCTS.DECREMENT_PRODUCT_INVENTORY}`, { id: product.id }, { root: true }) } } } // mutations const mutations = { [CART.PUSH_PRODUCT_TO_CART] (state, { id }) { state.items.push({ id, quantity: 1 }) }, [CART.INCREMENT_ITEM_QUANTITY] (state, { id }) { const cartItem = state.items.find(item => item.id === id) cartItem.quantity++ }, [CART.SET_CART_ITEMS] (state, { items }) { state.items = items }, [CART.SET_CHECKOUT_STATUS] (state, status) { state.checkoutStatus = status } } export default { namespaced: true, state, getters, actions, mutations }
// products.js
import shop from '../../api/shop' import {PRODUCTS} from '../mutations-types' // initial state const state = { all: [] } // getters const getters = {} // actions const actions = { getAllProducts ({ commit }) { shop.getProducts(products => { commit(PRODUCTS.SET_PRODUCTS, products) }) } } // mutations const mutations = { [PRODUCTS.SET_PRODUCTS] (state, products) { state.all = products }, [PRODUCTS.DECREMENT_PRODUCT_INVENTORY] (state, { id }) { const product = state.all.find(product => product.id === id) product.inventory-- } } export default { namespaced: true, state, getters, actions, mutations }
// index.js
import Vue from 'vue'
import Vuex from 'vuex'
import cart from './modules/cart'
import products from './modules/porducts'

Vue.use(Vuex)
export default new Vuex.Store({
  state: {
    userInfo: {
      email: "wl"
    }
  },
  modules: {
    cart,
    products
  },
})
// mutations-types.js
export const CART = { PUSH_PRODUCT_TO_CART: 'pushProductToCart', INCREMENT_ITEM_QUANTITY: 'incrementItemQuantity', SET_CART_ITEMS: 'setCartItems', SET_CHECKOUT_STATUS: 'setCheckoutStatus', } export const PRODUCTS = { SET_PRODUCTS:'setProducts', DECREMENT_PRODUCT_INVENTORY: 'decrementProductInventory' }

组件代码

主页:

<template>
  <div id="app">
    <h1>购物车示例</h1>
    <p>账号: {{email}}</p>
    <hr>
    <h2>产品</h2>
    <ProductList/>
    <hr>
    <ShoppingCart/>
  </div>
</template>

<script>
import { mapState } from 'vuex'
import ProductList from './day04_components/products'
import ShoppingCart from './day04_components/shoppingCart'
export default {
  computed: mapState({
    email: state => state.userInfo.email
  }),
  components: { ProductList, ShoppingCart },
}
</script>

清单:

<template>
  <div class="cart">
    <h2>清单</h2>
    <p v-show="!products.length"><i>请添加产品到购物车</i></p>
    <ul>
      <li
        v-for="product in products"
        :key="product.id">
        {{ product.title }} - {{ product.price }} x {{ product.quantity }}
      </li>
    </ul>
    <p>合计: {{ total }}</p>
    <p><button :disabled="!products.length" @click="checkout(products)">提交</button></p>
    <p v-show="checkoutStatus">提交 {{ checkoutStatus }}.</p>
  </div>
</template>

<script>
import { mapGetters, mapState } from 'vuex'
export default {
  computed: {
    ...mapState({
      checkoutStatus: state => state.cart.checkoutStatus
    }),
    ...mapGetters('cart', {
      products: 'cartProducts',
      total: 'cartTotalPrice'
    }),
    // ...mapGetters({
    //   products: 'cart/cartProducts',
    //   total: 'cart/cartTotalPrice'
    // })
  },
  // computed: {
  //   checkoutStatus(){
  //     return this.$store.state.cart.checkoutStatus
  //   },
  //   products() {
  //     return this.$store.getters['cart/cartProducts']
  //   },
  //   total() {
  //     return this.$store.getters['cart/cartTotalPrice']
  //   }
  // },
  methods: {
    checkout (products) {
      this.$store.dispatch('cart/checkout', products)
    }
  },
}
</script>

产品列表:

<template>
  <ul>
    <li
      v-for="product in products"
      :key="product.id">
      {{ product.title }} - {{ product.price }}
      <br>
      <button
        :disabled="!product.inventory"
        @click="addProductToCart(product)">
        加入购物车
      </button>
    </li>
  </ul>
</template>

<script>
import { mapState, mapActions } from 'vuex'
export default {
  computed: mapState({
    products: state => state.products.all,
  }),
  // computed: {
  //   products(){
  //     return this.$store.state.products.all
  //   }
  // },
  methods: mapActions('cart', [
    'addProductToCart'
  ]),
  // methods: {
  //   addProductToCart(product){
  //     this.$store.dispatch('cart/addProductToCart', product)
  //   }
  // },
  created () {
    this.$store.dispatch('products/getAllProducts')
  }
}
</script>

模拟数据:

const _products = [
    {"id": 1, "title": "华为 Mate 20", "price": 3999, "inventory": 2},
    {"id": 2, "title": "小米 9", "price": 2999, "inventory": 1},
    {"id": 3, "title": "OPPO R17", "price": 2999, "inventory": 5}
  ]
  
  export default {
    getProducts (cb) {
      setTimeout(() => cb(_products), 100)
    },
  
    buyProducts (products, cb, errorCb) {
      setTimeout(() => {
        // simulate random checkout failure.
        Math.random() > 0.5
          ? cb()
          : errorCb()
      }, 100)
    }
  }

效果图:

 

 

 

a

posted @ 2020-03-08 15:52  狗亮  阅读(180)  评论(0编辑  收藏  举报