vuex常用辅助函数以及源码解析

辅助函数

1. mapState

// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'

export default {
 computed: {
  localComputed () ,
  // 使用对象展开运算符将此对象混入到外部对象中
  ...mapState({
    // ...
  })
}
}
computed: mapState([
  // 映射 this.count 为 store.state.count
  'count'
])
export default {
  // ...
  computed: mapState({
    // 箭头函数可使代码更简练
    count: state => state.count,

    // 传字符串参数 'count' 等同于 `state => state.count`
    countAlias: 'count',

    // 为了能够使用 `this` 获取局部状态,必须使用常规函数
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
  })
}
  • 其实使用过 Vuex 的同学都知道,我们在页面或者组件中都是通过 this.$store.xxx 来调用的,那么其实,我们只要把你所创建的store对象赋值给页面或者组件中的$store变量即可

2. mapGetters

const store = new Vuex.Store({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    doneTodos: state => {
      return state.todos.filter(todo => todo.done)
    }
  }
})
import { mapGetters } from 'vuex'

export default {
  // ...
  computed: {
  // 使用对象展开运算符将 getter 混入 computed 对象中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
  }
}

...mapGetters({
  // 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
  doneCount: 'doneTodosCount'
})

3. mapActions

import { mapActions } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions([
      'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`

      // `mapActions` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
    })
  }
}

源码

全局混入Mixin

  • Vuex的原理通俗讲就是:利用了全局混入Mixin,将你所创建的store对象,混入到每一个Vue实例中,那么全局混入是什么呢?举个例子:
import Vue from 'vue'
// 全局混入
Vue.mixin({
  created () {
      console.log('handsome Boy')
  }
})

// 之后创建的Vue实例,都会输出'handsome Boy'
const a = new Vue({
  // 这里什么都没有,却能实现输出'handsome Boy'
})
// => "handsome Boy"
const b = new Vue({
  // 这里什么都没有,却能实现输出'handsome Boy'
})
// => "handsome Boy

上面例子看懂的人,就知道了,同理,把console.log(‘handsome Boy’)这段代码换成一段能做这件事的代码:把store赋值给实例的$store属性,就实现了:
在这里插入图片描述

代码实现

// vuex.js
let Vue;

// install方法设置,是因为Vue.use(xxx)会执行xxx的install方法
const install = (v) => { // 参数v负责接收vue实例
    Vue = v;
    // 全局混入
    Vue.mixin({
        beforeCreate() {
            if (this.$options && this.$options.store) {
                / * 根页面,直接将身上的store赋值给自己的$store,至于怎么判断是根页面的, 看最下面的解析1 .
                这也解释了为什么使用vuex要先把store放到入口文件main.js里的根Vue实例里*/
                this.$store = this.$options.store;
            } else {
                // 除了根页面以外,将上级的$store赋值给自己的$store
                this.$store = this.$parent && this.$parent.$store;
            }
        },
    })
}

// 创建类Store
class Store {
    constructor(options) { // options接收传入的store对象
        this.vm = new Vue({
            // 确保state是响应式
            data: {
                state: options.state
            }
        });
        // getter
        let getters = options.getters || {};
        this.getters = {};
        console.log(Object.keys(this.getters))
        Object.keys(getters).forEach(getterName => {
            Object.defineProperty(this.getters, getterName, {
                get: () => {
                    return getters[getterName](this.state);
                }
            })
        })
        // mutation
        let mutations = options.mutations || {};
        this.mutations = {};
        Object.keys(mutations).forEach(mutationName => {
            this.mutations[mutationName] = payload => {
                mutations[mutationName](this.state, payload);
            }
        })
        // action
        let actions = options.actions || {};
        this.actions = {};
        Object.keys(actions).forEach(actionName => {
            this.actions[actionName] = payload => {
                actions[actionName](this.state, payload);
            }
        })
    }
    // 获取state时,直接返回
    get state() {
        return this.vm.state;
    }
    // commit方法,执行mutations的'name'方法
    commit(name, payload) {
        this.mutations[name](payload);
    }
    // dispatch方法,执行actions的'name'方法
    dispatch(name, payload) {
        this.actions[name](payload);
    }
}

// 把install方法和类Store暴露出去
export default {
    install,
    Store
}

使用解析
// index.js
import Vue from 'vue';
import vuex from './vuex'; // 引入vuex.js暴露出来的对象
Vue.use(vuex); // 会执行vuex对象里的install方法,也就是全局混入mixin

// 实例一个Store类,并暴露出去
export default new vuex.Store({
    state: {
        num: 1
    },
    getters: {
        getNum(state) {
            return state.num * 2;
        }
    },
    mutations: { in (state, payload) {
            state.num += payload;
        },
        de(state, payload) {
            state.num -= payload;
        }
    },
    actions: { in (state, payload) {
            setTimeout(() => {
                state.num += payload;
            }, 2000)
        }
    }
})

// main.js
import Vue from 'vue';
import App from './App.vue'

import store from './store/index'; // 引入刚刚的index.js


new Vue({
    store, // 把store挂在根实例上
    el: '#app',
    components: {
        App
    },
    template: '<App/>',
})

解析补充

  1. 我们打印一下工程项目中最开始的实例对象
    在这里插入图片描述
    打印结果 :
    在这里插入图片描述
    因此创建vue实例后, $opations 可以拿到Store的所有数据。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值