Skip to content

Latest commit

 

History

History
174 lines (156 loc) · 4.78 KB

3.4.Vuex中辅助函数实现说明.md

File metadata and controls

174 lines (156 loc) · 4.78 KB

方便的组件api

为了避免每次都需要通过this.$store来调用api,vuex提供了mapState、mapMutations、mapGetters mapActions、createNamespacedHelpers 等api, 可以很方便的在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="!products.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
    ...mapState({
      checkoutStatus: state => state.cart.checkoutStatus
    }),
    //这里使用了mapGetters
    ...mapGetters('cart', {
      products: 'cartProducts',
      total: 'cartTotalPrice'
    })
  },
  methods: {
    checkout (products) {
      this.$store.dispatch('cart/checkout', products)
    }
  }
}
</script>

以上是vuex官方示例shopping-cart中一个组件(examples/shopping-cart/components/ShoppingCart.vue)。同样的,我们还能这样使用mapActions和mapMutations。

<script>
import { mapActions mapMutations } from 'vuex'

export default {
  //...
  methods: {
    //这里使用了mapActions
    ...mapActions('cart', [
      'addProductToCart'
    ]),
    //这里使用了mapMutations
    ...mapMutations({
      decrement: 'decrementProductInventory'
    })
  }
  //...
}
</script>
  • 注:`...用的是es6中的对象展开式写法。

组件api实现解析

这几个组件api放在helpers.js文件中,我们先来看看mapState函数的源码。

//normalizeNamespace是进行参数处理,如果存在namespace便加上命名空间
export const mapState = normalizeNamespace((namespace, states) => {
  const res = {}
  //normalizeMap是对传入的states进行处理,也就是数据格式的统一
  normalizeMap(states).forEach(({ key, val }) => {
    //遍历,对参数里的所有state都包裹一层函数,最后返回一个对象
    res[key] = function mappedState () {
      let state = this.$store.state
      let getters = this.$store.getters
      if (namespace) {
        //如果存在namespace,取该namespace下module的state和getters
        const module = getModuleByNamespace(this.$store, 'mapState', namespace)
        if (!module) {
          return
        }
        state = module.context.state
        getters = module.context.getters
      }
      //val是函数,把state和getters传递进去
      return typeof val === 'function'
        ? val.call(this, state, getters)
        : state[val]
    }
    // mark vuex getter for devtools
    res[key].vuex = true
  })
  return res
})

这里我们回顾一下上面mapState的用法:

import { mapState } from 'vuex'
export default {
  computed: {
    //这里使用mapState
    ...mapState({
      checkoutStatus: state => state.cart.checkoutStatus
    })
  }
  /** 省略 **/
}

经过 mapState 函数处理后的结果:

import { mapState } from 'vuex'
export default {
  computed: {
    checkoutStatus() {
      return this.$store.state.cart.checkoutStatus
    }
  }
  /** 省略 **/
}

对比上面的mapState的用例和经过mapState函数处理后的结果,就可以很清楚的知道mapState函数就是在每个state包装一下,使原本需要在this.$store上取state的写法 变成 state => stat.cart 的写法而已。

同样的我们再来对比下mapGetters的写法和处理结果

//使用mapGetters的写法
import { mapGetters } from 'vuex'

export default {
  computed: {
    //这里使用了mapGetters
    ...mapGetters('cart', {
      products: 'cartProducts',
      total: 'cartTotalPrice'
    })
  },
  /** 省略 **/
}
//mapGetters处理后的结果
export default {
  computed: {
    products() {
      return this.$store.getters['cart']['cartProducts']
    },
    total() {
      return this.$store.getters['cart']['cartTotalPrice']
    }
  }
  /** 省略 **/
}

好,现在是彻底明白了,mapState、mapGetters函数其实就相当于一种语法糖,将原本需要this.$store来获取数据的写法变成另外一种更加简易的写法。

mapActions、mapMutations的功能大同小异,这里就不再赘写了。

小结

本节主要就讲mapState、mapMutations、mapGetters、mapActions这几个函数功能的实现,当然还有其他一些辅助函数或工具函数就留下自己去看吧。

到此,vuex的源码解析就结束吧。不难,我们再整理下要点: