zoukankan      html  css  js  c++  java
  • 手写VUE-ROUTER 2

    2020-10-19
    手写VUE-ROUTER 2
    static install(Vue): void 静态方法
    • 在VueRouter的实现中 第一个需要定义一个静态方法install
    • 这个方法在Vue.use(VueRouter)的时候会调用这个方法 并传入Vue构造函数
    Vue.use(VueRouter);
    • 在这个静态方法中 设置一个变量 installed 来判断这个插件是否已经被安装
    • 由于在实现过程中多次会用到Vue的构造函数 所以把他存在全局 copyVue
    • 同时 在Vue的原型上使用混入mixin的方式 在create生命周期中添加一些处理
    • 注意:
    • 在create生命周期中 我们需要在初始化Vue实例的时候 把router挂载到Vue的原型上
    • 这样 以后所有的VueComponent 就可以通过原型链访问到router了
    • 如果不挂载到原型上 那么整个Vue中只有Vue实例能访问到router VueComponent是访问不到的
    • 挂载完成后 此时已经有VueRouter的实例 那么调用init方法 初始化组件和事件
    static install(Vue) {
        // console.log(this); // 这里的this是VueRouter的构造函数 所以不能调用init 只有实例才能
        // 1. 判断当前插件是否已经安装
        // 在install静态方法中设置一个installed属性记录是否已经执行过install
        if (VueRouter.install.installed) { return; }
        VueRouter.install.installed = true;
        // 2. 把Vue的构造函数记录到全局变量
        copyVue = Vue;
        // 3. 把创建Vue实例时传入的router对象注入到所有的Vue实例上
        // 用混入的方式在vue事件的生命周期函数中添加 在beforeCreate生命周期函数中
        // this肯定是指向 Vue 的实例 此时可以找到 $options
        copyVue.mixin({
          beforeCreate() {
            // 如果是组件就不执行 如果是vue实例就执行 组件的 options 里没有 router 这个字段
            // 因为往vue原型上挂载$router只需要执行一次就行
            if (this.$options.router) {
              console.log(this); // 这个this就是Vue的实例
              console.log(copyVue.prototype); // 这个是Vue的构造函数 copyVue.prototype 是原型
              // 把这个实例的router上挂载到Vue原型上让每一个Vue的实例都有这个router
              copyVue.prototype.$router = this.$options.router;
              copyVue.prototype.name = 'lanpang 666';
              this.$options.router.init(); // 接line9 所以要在实例化之后再调用init
            }
          },
        });
      }
    构造函数:
    • 接收一个options 里面有路由规则
    • 在VueRouter类中添加一个routeMap 对象 数据格式是键值对的路由和组件
    • 通过Vue的静态方法observable在VueRouter类中添加一个响应式数据 data 里面有一个current记录当前路由
    • 响应式数据当数据变化时 依赖于这个数据的视图会发生变化
    constructor(options) {
        this.options = options;
        this.routeMap = {};
        // data 是一个响应式的对象
        // Vue 中提供的 observable 可以创建一个响应式对象
        // 这个响应式对象可以直接用在渲染函数和计算属性里面
        this.data = copyVue.observable({
          // 当前路由地址 变化时router-view 中 const el = self.routeMap[self.data.current];
          // 所以router-view render的组件依赖于这个响应式数据 所以也会发生变化
          current: '/',
        });
      }
    createRouteMap:
    • 把构造函数中 传过来的选项中的 rules 转换成键值对的形式存储到 routeMap对象中去
    initEvent:
    • 注册 popstate 事件 处理浏览器上点击前进后退
    initComponents:
    • 注册 router-view 和 router-link 组件
    • router-link
    • 接收一个props to 是要去的路由
    • 用render方法渲染一个a标签作为router-link 并且把to作为a标签的href属性的值
    • 在往这个a标签上注册一个click事件 点击时触发组件中的clickHandler
    • 通过window.history.pushState(state, title, url);的方法改变URL地址
    • 同时更新router实例中的data里的current也为url 并阻止浏览器的跳转行为
    • router-view
    • 用render方法根据 this.data.current 的路径去 routeMap中找到对应组件
    • 将这个组件渲染到 route-view 上
    let copyVue = null;
    
    class VueRouter {
      // Vue.use传入 VueRouter 的时候会调用 VueRouter 下的 install 静态方法
      // 调用install的时候会传两个参数 1、Vue的构造函数 2、可选的选项对象
    
      static install(Vue) {
        // console.log(this); // 这里的this是VueRouter的构造函数 所以不能调用init 只有实例才能
        // 1. 判断当前插件是否已经安装
        // 在install静态方法中设置一个installed属性记录是否已经执行过install
        if (VueRouter.install.installed) { return; }
        VueRouter.install.installed = true;
        // 2. 把Vue的构造函数记录到全局变量
        copyVue = Vue;
        // 3. 把创建Vue实例时传入的router对象注入到所有的Vue实例上
        // 用混入的方式在vue事件的生命周期函数中添加 在beforeCreate生命周期函数中
        // this肯定是指向 Vue 的实例 此时可以找到 $options
        copyVue.mixin({
          beforeCreate() {
            // 如果是组件就不执行 如果是vue实例就执行 组件的 options 里没有 router 这个字段
            // 因为往vue原型上挂载$router只需要执行一次就行
            if (this.$options.router) {
              console.log(this); // 这个this就是Vue的实例
              console.log(copyVue.prototype); // 这个是Vue的构造函数 copyVue.prototype 是原型
              // 把这个实例的router上挂载到Vue原型上让每一个Vue的实例都有这个router
              copyVue.prototype.$router = this.$options.router;
              copyVue.prototype.name = 'lanpang 666';
              this.$options.router.init(); // 接line9 所以要在实例化之后再调用init
            }
          },
        });
      }
    
      constructor(options) {
        this.options = options;
        this.routeMap = {};
        // data 是一个响应式的对象
        // Vue 中提供的 observable 可以创建一个响应式对象
        // 这个响应式对象可以直接用在渲染函数和计算属性里面
        this.data = copyVue.observable({
          // 当前路由地址 变化时router-view 中 const el = self.routeMap[self.data.current];
          // 所以router-view render的组件依赖于这个响应式数据 所以也会发生变化
          current: '/',
        });
      }
    
      init() {
        this.createRouteMap();
        this.initComponents(copyVue);
        this.initEvent();
      }
    
      // createRouteMap 把构造函数中 传过来的选项中的 rules 转换成键值对的形式存储到 routeMap对象中去
      createRouteMap() {
        this.options.routes.forEach((route) => {
          this.routeMap[route.path] = route.component;
        });
      }
    
      // 这个函数是实现 router-link router-view 两个组件
      initComponents(Vue) {
        const self = this;
    
        Vue.component('router-link', {
          props: {
            to: String,
          },
          // template: `<a :href="to"><slot></slot></a>`,
          render(h) {
            return h('a', {
              attrs: {
                href: this.to,
              },
              on: {
                click: this.clickHandler,
              },
            }, [this.$slots.default]);
          },
          methods: {
            clickHandler(e) {
              // console.log(this); // 这里是VueComponent
              window.history.pushState({}, '', this.to);
              this.$router.data.current = this.to;
              e.preventDefault();
            },
          },
        });
    
        Vue.component('router-view', {
          render(h) {
            const el = self.routeMap[self.data.current];
            return h(el);
          },
        });
      }
    
      // 注册 popstate 事件 处理浏览器上点击前进后退
      initEvent() {
        window.addEventListener('popstate', () => {
          console.log('initEvent');
          this.data.current = window.location.pathname;
        });
      }
    }
    
    export default VueRouter;
    思考:
    • 在new Vue的时候传入了router的实例 这个实例会挂载到Vue实例的$options中
    • 所以在Vue的实例中可以拿到 router 的实例
    • 那为什么在VueComponent中 无法直接拿到 router
    • 而是需要通过install方法里混入mixin中手写到Vue的原型上
    // new Vue 传入的对象会存入 Vue 实例的options中
    // 所以在这个实例Vue中可以拿到 router
    new Vue({
      router,
      store,
      render: (h) => h(App),
    }).$mount('#app');
  • 相关阅读:
    NYOJ232 How to eat more Banana
    NYOJ716 River Crossing(第六届河南省程序设计大赛)
    HDOJ1847 Good Luck in CET4 Everybody!
    NYOJ234 吃土豆
    HDOJ1850Being a Good Boy in Spring Festival
    HDOJ2176 取(m堆)石子游戏
    NYOJ78 圈水池(简单凸包)
    POJ1656 Counting Black (二维树状数组)
    HDOJ1892 See you~(二维树状数组)
    取石子问题 – 1堆
  • 原文地址:https://www.cnblogs.com/lanpang9661/p/13843286.html
Copyright © 2011-2022 走看看