Code前端首页关于Code前端联系我们

全家桶原理vue2

terry 2年前 (2023-09-08) 阅读数 164 #Vue

Vuex原理解析

vuex的设计理念是:集中状态管理,状态变化可预测

插件

使用vuex时,必须先安装Vue.use(Vuex),即安装vuex插件。

  • 如何实现插件?

    很简单,install()方法暴露在外。

  • 这个补充剂的主要功能是什么?

    安装$store。由于Vue.use()先执行,且new Vue()的实例尚未创建,因此在延迟安装中使用mixin进行混合。

function install(_Vue) {
//Vue.use() 可以接收到Vue实例
  Vue = _Vue

  Vue.mixin({
    beforeCreate() {
      // 因为使用混入,钩子在每个组件创建实例时都会调用
      // 根实例才有该选项
      if (this.$options.store) {
        //挂载vue原型方便其他组件调用$store
        Vue.prototype.$store = this.$options.store
      }
    }
  })
}
 

状态 反应式状态管理

  • 有多少种方法来实现数据响应?
  1. Object.defineProperty()
  2. Vue.util.defineReactive()
  3. Vue.observable()
  4. new Vue({data(){}})

这里使用第四种

new Vue({
  data: {
    //$$state为什么用$$不代理,外部不能访问
    $$state:options.state
  }
})
 

state包装

//只读state,可以获取数据
get state() {
    return this._vm._data.$$state
}

set state(v) {
    console.error('please use replaceState to reset state');
}
 

实现commit()dispatch()方法

输入方法名称和参数,前往mutationsactions匹配

// 保存mutaions和actions选项
    this._mutations = options.mutations;
    this._actions = options.actions;
    
 commit(type, payload) {
    const entry = this._mutations[type]
    if (!entry) {
      console.error('unkown mutation type');
    }
    //传入state
    entry(this.state, payload)
  }
  
  dispatch(type, payload) {
    const entry = this._actions[type]
    if (!entry) {
      console.error('unkown action type');
    }
    //{commit}上下文对象就是当前实例this
    entry(this, payload)
  }
 

this 绑定到

this.commit = this.commit.bind(this)
this.dispatch = this.dispatch.bind(this)
 

到达getters

vuegetters使用计算属性vue进行实时数据监控
this._wrappedGetters = options.getters
//外界通过$store.getters.xxx访问getters
this.getters = {};
//定义computed数据
const computed = {};
//获取当前this
const store =this;
Object.keys(this._wrappedGetters).forEach(key => {
    //this指向发生改变,用上方定义好的this
    const fn = store._wrappedGetters[key]
    //computed是无参数函数,而getters是有参数函数,所以高阶函数包一下
    computed[key] = function(){
        return fn(store.state)
    }
})
//指定getters为只读属性
Object.defineProperty(store.getters,key,{
   get: () => store._vm[key]
})

this._vm = new Vue({
  data: {
    $$state: options.state  // $$不代理,外部不能直接访问
  },
  computed
})
 

vue-router原理

如果在一页程序中更改url,则视图

对应的内容不会刷新。

实现插件并安装$router

// 参数1是Vue.use调用时传入的
VueRouter.install = function(_Vue) {
  Vue = _Vue;

  // 1.挂载$router属性
  //Vue.use()优先执行,此时new Vue()还没有执行,所以要延迟执行$router挂载
  // 全局混入目的:延迟下面逻辑到router创建完毕并且附加到选项上时才执行
  Vue.mixin({
    //new Vue()第一个执行的钩子函数  
    beforeCreate() {
      // 因为使用混入,钩子在每个组件创建实例时都会调用
      // 根实例才有该选项
      if (this.$options.router) {
        //挂载vue原型方便其他组件调用$router  
        Vue.prototype.$router = this.$options.router;
      }
    },
  });

 

更改网址页面不刷新

哈希

#/user/1 hash 模式将带有“#”并且不会刷新浏览器。
跟随 hashchange 进行 url

的更改

历史

/user/1 history正常url形状
有监控popstate监控url变化

响应数据,url改变内容,重新渲染

Vue.util.defineReactive指定响应数据

 //定义响应式matched数组,存放当前路由匹配的嵌套组件
 Vue.util.defineReactive(this,'matched',[]);
 //遍历路由表routes
 this.match();
 
 match(routes){
      //路由表
      let routes = routes || this.$options.routes;
      //递归遍历路由表
      for(route of routes){
          if(route.path === '/' && this.current === '/'){
              //添加路由信息
              this.matched.push(route);
              return;
          }
          //  /about/info
          if(route.path !== '/' && this.current.indexOf(route.path) != -1){
              //包含/about
              this.matched.push(route);
              //还有嵌套子路由,递归调用match
              if(route.children.length > 0){
                  this.match(route.children)
              }
              return;
          }
      }
  }
}
 

实现两个全局组件 router-link 和 router-view

实施路由器链路

实施标记 a <a href="xxx">user</a>

Vue.component("router-link", {
    props: {
      to: {
        type: String,
        required: true,
      },
    },
    render(h) {
      // <a href="to">xxx</a>
      // return <a href={'#'+this.to}>{this.$slots.default}</a>
      return h(
        "a",
        {
          attrs: {
            href: "#" + this.to,
          },
        },
        this.$slots.default
      );
    },
  });
 

router-view的实现

深度判断router-view实现布线嵌套;通过矩阵渲染嵌套组件 matched

Vue.component("router-view", {
    render(h) {
      //标记当前router-view深度
      this.$vnode.data.routerView = true;  
      //深度标识 
      let depth = 0;
      //向上查找routerView
      let parent = this.$parent;
      while(parent){
          const vnodeData = parent.$vnode && parent.$vnode.data;
          if(vnodeData.routerView){
              //说明parent是个router-view
              depth++;
          }
          parent = parent.$parent;
      }
      // 获取当前路由对应的组件
      let component = null;
      //matched是响应式的所以动态渲染路由
      const route = this.$router.matched[depth];
      if (route) {
        component = route.component
      }
      console.log(this.$router.matched, component);
     
      return h(component);
    },
  });
};
 

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门