vuex源码解析及简单实现

摘要:
你可以把Vue.use方法理解为:Vue.use==˃{object.install}思考:故我们重构的vuex需要对外暴露一个install方法2.newVuex.Store()conststore=newVuex.Store解析:从newVuex.Store()可以看出导入的Vuex包含着一个名为Store的构造函数。思考:综合以上两点,我们可以推断出在vuex文件的导出内容大致为:exportdefault{install:=˃{//todo},Store:=˃{  //vuex的核心代码  }}3.actionconststore=newVuex.Store({actions:{addCount({commit},payload){    commit("changeCount",payload)}}state:{...},mutations:{...},getters:{...}}解析:这种是官方推荐的结构写法,你也可以这么写addCount(context,payload){  context.commit("changeCount",payload)}解析:第二种写法种的参数context是指上下文环境即这个store实例。
vuex源码解析
目录

一、vuex的使用回顾

//store/index.js
import Vuex from "vuex"
import Vue from "vue"
Vue.use(Vuex)
const store = new Vuex.Store({
        state: {
        count: 0
    }
    getters: {
        getCount: (state) => {return state.count}
    },
    mutations: {
        changeCount(state, payload) {
            state.count = payload
        },
   },
    actions: {
        addCount({commit},payload) {
        commit("changeCount",payload)
        }
    }
})
export default store
//main.js
import store from "./store"
new Vue({
    el: "#app",
    store
})

二、逐句剖析vuex的使用

1. vue.use( )

import Vue from 'vue' 
import Vuex from 'vuex'
Vue.use(Vuex)

解析: 上文中的 Vue.use(Vuex)会自动调用Vuex 这个对象的install方法, 并在install中传入 Vue 实例,来保证内外的Vue实例一致。你可以把Vue.use方法理解为:Vue.use = ( object ) => { object.install( this )}

思考:故我们重构的 vuex 需要对外暴露一个install 方法

2. new Vuex.Store( )

const store = new Vuex.Store({
  state: {...},
  getters: {...},
  mutations: {...},
  actions: {...}
})

解析:new Vuex.Store()可以看出导入的Vuex包含着一个名为 Store的构造函数。

思考:综合以上两点,我们可以推断出在 vuex 文件的导出内容大致为:

export default {
    install: (vue)=> { 
        //todo 
    },
    Store: ({state,getters,actions,mutations})=> {
      //vuex的核心代码 
  }
} 

3. action

const store = new Vuex.Store({
    actions: {
        addCount({commit},payload) {
        commit("changeCount",payload)
        }
    }
    state:{...},
    mutations: {...},
    getters: {...}
}

解析: 这种是官方推荐的结构写法,你也可以这么写

addCount(context,payload) {
  context.commit("changeCount",payload)
}

解析: 第二种写法种的参数context是指上下文环境即这个store实例。上文中的第一种写法,既然可以从这个context中解构出commit方法,不难得出这个store实例包含commit方法


三、刻画vuex 的大致结构

class Store {
  constructor({state, getters, mutations, actions}) {
      //todo
  }
}
function install(vue){
  //todo
}
export default {
  Store,
  install
}

四、完成 install 方法

思考: 在使用官方的vuex后, 我们在每个组件中都可以访问到this.$store, 可是我们在main.js中只是把store挂载到根实例中,按理说只有在根实例中才可以访问到store

//main.js
import store from "./store"
new Vue({
    el: "#app",
    store
})

结论: 要在根实例中把store 赋值给$store,并且利用vue组件加载的先父后子原则,从根实例的子组件开始,每个组件都从父组件拿到$store,并将从父组件拿到的$store 赋值给自己的$store属性,从而实现每个组件都拥有$store属性,并且都指向同一个store实例

let Vue
let install = (_Vue) => {
    Vue = _Vue
  // 通过混入beforeCreate生命周期的钩子函数,使每个vue组件都挂载上store
    Vue.mixin({
        beforeCreate(){
        //this指向每个执行的 vue 组件
        //先判断当前的this是不是根实例,因为第一次执行只有根实例上的$options有store实例
            if(this.$options.store){
          //根实例
          this.$store = this.$options.store
            } else{
          //所以从根实例为一级组件开始,二级组件可以通过this.$parent 
          //拿到一级组件的store, 然后挂载到自己身上的$store
          //如此反复 每个组件都挂载上 $store
                this.$store = this.$parent && this.$parent.$store
            }
        }
    })
}
export default install

五、完成 Store 中的 state

思考: store 中 state 的响应式是利用vue中data的响应式来实现的

import install from './intsall.js'

class Store {
    constructor({state,getters,mutations,actions}){
        this.vm = new Vue ({
            data: {
                state
            }
        })
  }
}

export default {
    install,
    Store
}

六、完成 Store 中的 getters

提示: 为了方便读者理解,接下来的内容我们会先列出用法,再展示功能实现代码

getters: {
    getCount: (state) => {return state.count}
},

提示: 功能实现代码如下:

class Store {
    /***** state code *****/
  constructor({state,getters,mutations,actions}){
    this.vm = new Vue ({
            data: {
                state
            }
        })
  }
  
  /***** getters code ****/
  
  this.getters = {}
  for(let getterName in getters){
      // 利用Object.deineProperty 对this.getter 进行访问劫持
      Object.defineProperty(this.getters,getterName,{
      get: ()=>{
          //getter.getCount = (state) => {return state.count}
        return getter[getterName](this.vm.state)
      }
    })
  }
}

七、完成 Store 中的 mutations

提示: 原生使用语法如下:

mutations: {
    changeCount(state, payload) {
        state.count = payload
    },
},

提示: 功能实现代码如下:

class Store {
    /***** state code *****/
  constructor({state,getters,mutations,actions}){
    this.vm = new Vue ({
            data: {
                state
            }
        })
  }
  
  /***** mutations code ****/
  this.mutations = {}
  Object.keys(mutations).forEach( mutationName => {
    this.mutations[mutationName] = (newValue)=> {
      mutation[mutationName](this.vm.state,newValue)
    }
  })
}

八、完成 Store 中的 commit

提示: 原生使用语法如下:

addCount({commit},payload) {
    commit("changeCount",payload)
}

提示: 功能实现代码如下:

class Store {
    /***** state code *****/
  constructor({state,getters,mutations,actions}){
    this.vm = new Vue ({
            data: {
                state
            }
        })
  }
  
  /***** commit code ****/
  this.commit = (mutationName,newValue)=> {
        this.mutations[mutationName](newValue)
  }
}

九、完成 Store 中的 actions

提示: 原生使用语法如下:

actions:{
    addCount(context,payload) {
      context.commit("changeCount",payload)
    }
}

提示: 功能实现代码如下:

class Store {
    /***** state code *****/
  constructor({state,getters,mutations,actions}){
    this.vm = new Vue ({
            data: {
                state
            }
        })
  }
  
  /***** actions code ****/
  this.actions = {}
  Object.keys(actions).forEach(actionName => {
    this.actions[actionName] = (newValue)=> {
      actions[actionName](this, newValue)
    }
  })
}

免责声明:文章转载自《vuex源码解析及简单实现》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Apache Shiro(六)-基于URL配置权限[转]C#中用NamedPipe进程间通信下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

VUE 使用中踩过的坑

vue如今可谓是一匹黑马,github star数已居第一位!前端开发对于vue的使用已经越来越多,它的优点就不做介绍了,本篇是我对vue使用过程中以及对一些社区朋友提问我的问题中做的一些总结,帮助大家踩坑。如果喜欢的话可以点波赞,或者关注一下,希望本文可以帮到大家! 1.路由变化页面数据不刷新问题 出现这种情况是因为依赖路由的params参数获取写在cr...

----Vue 中mixin 的用法详解----

说下我对vue中mixin的一点理解   vue中提供了一种混合机制--mixins,用来更高效的实现组件内容的复用。最开始我一度认为这个和组件好像没啥区别。。后来发现错了。下面我们来看看mixins和普通情况下引入组件有什么区别?      组件在引用之后相当于在父组件内开辟了一块单独的空间,来根据父组件props过来的值进行相应的操作,单本质上两者还是...

ubuntu13.04下载android4.0.1源码过程

最初我参考的是老罗的博客http://blog.csdn.net/luoshengyang/article/details/6559955 进行下载安装的,但弄着弄着就发现不太对劲了。这里记录下详细过程: 1,我的前提是已经搭建好了Android开发环境,也即jdk已经安装好了,输入java -version来检查是否成功。搭建android开发环境可以...

详解S7源码3-COTP and TPKT

连接 S7COMM简介 https://www.anquanke.com/post/id/186099 OSI layer    Protocol Application Layer    S7 communication Presentation Layer    S7 communication(COTP) Session Layer    S7 co...

Hadoop源码分析5: RPC基本线程

1. 数据记录FileStatus public class FileStatus implements Writable {       private String filename;        private long time;        static {  // register IPCFileStatus        Writab...

vue中的父子组件之间的通信--新增、修改弹框

在一个vue页面中有时候内容会很多,为了方便编写查看,可以分为多个子组件,最后在父组件中引入对应的子组件即可。 下面这个是父子组件通信中的一个具体实例:新增、修改弹框。子组件中主要写了关于新增、修改的弹框, 子组件: 1.弹框: <div class="newDocuments"> <div class="newDocuments_...