zoukankan      html  css  js  c++  java
  • 手撕VUE源码(二):vuex的底层实现

    let Vue; //vue的构造函数
    
      // modules:{
      //   state: 1,
      //   modules:{
      //     a:{
      //       state:2
      //     },
      //     b:{
      //       state:3
      //     }
      //   }
      // }
    class ModuleCollection{
      constructor(options){
        this.register([],options);
      }
      //深度优先遍历
      register(path,rootModule){
        //1、定义一个新的子模块
        let newModule = {
          _raw: rootModule,
          _children: {},
          state: rootModule.state
        }
        //2、挂载根源模块
        if(path.length === 0){
          this.root = rootModule
        }
        //6、挂载子模块,将此时遍历到的模块挂载到对应父节点上,第二遍递归时才开始走这个判断
        if(path.length != 0){
          //7、根据path数组,找到rootModule此时对应的父节点
          let parent = path.slice(0,-1).reduce((root,current) => {
            return root._children[current];
          },this.root);
          //8、挂载至父节点
          parent._children[path[path.length - 1]] = newModule;
        }
        //3、查询是否有子模块
        if(rootModule.modules){
          //4、对子模块进行遍历
          forEach(rootModule.modules,(moduleName,module) => {
            //5、对子模块进行递归处理
            this.register(path.concat(moduleName),module);
          })
        }
      }
    }
    
    class Store{
      //用户传入options,我们首先的任务是将options中的属性和方法,绑定到store自身作用域上
      constructor(options){
        //先绑定state属性
        this._s = new Vue({ //给state加上数据监听,使对应视图实时响应刷新
          data: {
            state: options.state
          }
        })
    
        new ModuleCollection(options); //数据层级整理
        //getters相当于computed
        let getters = options.getters || {}
        this.getters = {};
        //再将getters属性中的各个方法绑定到this.getters的中,执行这些方法时自动传入state
        Object.keys(getters).forEach((getterName => {
          Object.defineProperties(this.getters,getterName,{
            //此处使用箭头函数锁定this上下文,防止因调用者变化使this变更
            get:()=>{
              return getters[getterName](this.state);
            }
          })
        }))
        
        //mutations相当于method
        let mutations = options.mutations || {}
        this.mutations = {};
        Object.keys(mutations).forEach(mutationName => {
          //将私有属性mutations的方法绑定到实例属性this.mutations上
          this.mutations[mutationName] = (preload) =>{
            //执行私有属性mutations上对应的方法
            mutations[mutationName](this.state,preload);
          }
        })
      }
      //用户的调用入口
      commit = (type,payload) => {
        this.mutations[type](payload);
      }
      //可以通过get、set控制state存取
      get state(){
        return this._s
      }
    }
    
    const install = (_Vue) =>  {
      Vue = _vue;
      Vue.mixin({
        //声明混入对象的声明周期,在每个组件创建之前加入store
        beforeCreate(){
          //判断父组件还是子组件,如果是子组件则把父组件的store传给子组件
          if(this.$options && this.$options.store){
            this.$store = this.$options.store
          }else{
            this.$store = this.$parent && this.$parent.$store
          }
        }
      })
    }
    
    export default {
      install,  //vue.use方法在引入模块时,默认调用模块的install方法
      Store
    }
  • 相关阅读:
    Linux学习笔记总结--CentOS 设置静态IP
    LAMP环境部署总结
    expect批量分发公钥
    CentOS6.5一键安装MySQL5.5.32(源码编译)
    CentOS6.5 一键部署运行环境shell脚本
    CentOS 更新yum源
    centos 6.6编译安装nginx
    安装Oracle数据库和PLSQL连接数据库
    ABAP 取字段的简短描述
    ABAP OLE常用方法和属性
  • 原文地址:https://www.cnblogs.com/jiangxiaoxi/p/12617227.html
Copyright © 2011-2022 走看看