Vuex源码解析

手写vuex核心代码

vuex基本用法

//store/index.js
import Vue from 'vue'
import Vuex from 'Vuex' 

Vue.use(Vuex)// 很关键下面会将
let store = {
  state: {
  },
  getters: {
  },
  mutations: {
  },
  actions: {
  },
  modules: {
  }
}
export default new Vuex.Store(store)

分析

我们是通过new Vuex.store(option)获得一个store实例,也就是说vuex内部的源码的样子为

Class Store{
  constructor(options) { // this.$store
        //options为上面的store
  }
}

let Vuex = {
  Store
}

在vue项目中的使用

也就是说vuex本质上是一个拥有store类作为属性的一个对象,通过new Vuex.Store(store) 来使用,在vue项目中的使用方法为

import Vue from 'vue'
import App from './App.vue'
import store from './store' // store.js文件
Vue.config.productionTip = false

在.vue中使用方法为


也就是说每一个组件对象this上都会有$store这个属性,那么这个属性怎么来的呢?这就涉及到vue插件的使用了也就是上文store.js文件中的Vue.use(Vuex)//官网解释如下

Vue.use( plugin )

  • 参数

    • {Object | Function} plugin
  • 用法

    安装 Vue.js 插件。如果插件是一个对象,必须提供 install 方法。如果插件是一个函数,它会被作为 install 方法。install 方法调用时,会将 Vue 作为参数传入。

    该方法需要在调用 new Vue() 之前被调用。

    当 install 方法被同一个插件多次调用,插件将只会被安装一次。

install源码解析

也就是说vuex源码会有一个install方法,

Class Store{
  constructor(options) { // this.$store
        //options为上面的store
  }
}

let Vuex = {
  Store
}

export const install = (Vue) => {
    // 这里就会让vue的每一个组件对象this都能获取到$store,具体做法如下
    Vue.mixin({
        beforeCreate(){
            // 这里的this是vue的实例, this.$option.store 实际上在vue初识话的时候传入的store,也就是new Vue({store,...})
            //const vm = new Vue({
            //  store,// 将store类的实例也就是export default new Vuex.Store(store)传入到vue的构造函数中
            //  render: h => h(App)
            //}).$mount('#app')
            if (this.$options.store) { // 所以能获取到store的为根
                // this.$options.store => new Vuex.Store
                // this.$store =>  new Vuex.Store
                this.$store = this.$options.store; // 给根属性增加$store属性
            } else if (this.$parent && this.$parent.$store) {
                this.$store = this.$parent.$store
            }
        }
    })
}

这样每一个组件对象this上都会有store在每个组件的template模板中就可以使用vuex中存储的全局状态了

使用过vuex的都知道,vuex中的属性被修改后页面也会被重新编译,也就是可以达到像vue组件中的data中定义的属性一样,当data中的属性被修改后,template模板也会被重新编译,这就是vue的响应式系统,vuex中的state属性正是借助了vue的响应式系统实现的。所以vuex强依赖vue

vuex核心原理解析

// util方法
const forEachValue = (obj, cb) => {
    Object.keys(obj).forEach(key => cb(obj[key], key))
}
export class Store { // vuex 是基于Vue来实现的
    constructor(options) { // this.$store
        let computed = {}
        this.getters = {}
        forEachValue(options.getters, (value, key) => {
            computed[key] = () => { 
                return value.call(this, this.state);
            }
            Object.defineProperty(this.getters, key, {
                get: () => {
                    return this._vm[key]; 
                }
            })
        }) // getters 函数 和 “属性” 取值 
        this._vm = new Vue({
            data: {
                // // 内部会使用代理 把所有开头不为$的属性代理给this._vm
                $$state: options.state
            },
            computed
        }); 
        this.mutations = {};
        this.actions = {}
        forEachValue(options.mutations, (fn, key) => {
            this.mutations[key] = (payload) => fn.call(this, this.state, payload)
        });
        forEachValue(options.actions, (fn, key) => {
            this.actions[key] = (payload) => fn.call(this, this, payload)
        })
    }
    // 属性访问器
    get state() {
        return this._vm._data.$$state 
    }
    // 当用户调用this.$store.commit 方法的时候会调用这个方法
    commit = (type, payload) => { 
        this.mutations[type](payload)
    }
    dispatch = (type, payload) => {
        this.actions[type](payload)
    }
}

至此vuex的基本原理和源码分析完毕

你可能感兴趣的:(Vuex源码解析)