vue-router和react-router源码

spa页面路由的基本实现

  • hashChange(hash)或者onpopstate(pathname)监听url的改变
  • 路由的current的改变,重新获取新的组件渲染

vue-router的源码开发

vue的插件开发
  • vue.use()的作用:将传入的方法调用一遍,对象的话就会执行里面的install属性,install方法里面会获取到vue类参数,通过vue.mixin()将方法/属性混入vue的全局实例中;
  • 生命周期的方法注入
const plugin  = function(vue) {
  vue.mixin({
    data(){return {  }},
     methods: {},
      breforeCreate: function() { this去操作当前的组件 },
      created: function() {},
      mounted: function() {},
      updated: function() {},
      destroyed: function() {},
      .............
  })
}
  • vue内置的方法的使用
    1.vue.util: warn、extended、mergOptions、defineReactive(监听data)
vueRouter源码的实现
class historyRouter {
  constuctor() {
  this.current = null;
  }
}

class vueRouter {
  constructor(options) {
    this.mode = options.mode || hash;
    this.routers = options.routers || [];
     this.history = new historyRouter();
      this.routerMap = this.createMap(this.routes);
      this.init();
  }
  init() {
    if(this.mode === 'hash') {
      location.hash === '' ? '' : location.hash = '/' ; // 默认跳转到hash模式
       window.addEvenListeuener('load', fuction() {
              this.history.current = location.hash.slice(1);
      });
       window.addEvenListener('hashChange', fuction() {
              this.history.current = location. pathname;
      });
    }else {
       window.addEvenListeuener('load', fuction() {
              this.history.current = location.hash.slice(1);
      });
       window.addEvenListener('onpopstate', fuction() {
              this.history.current = location.history.slice(1);
      });
    }
  }
   createMap(router) { // 将传入的数组路由转换为键值对的形式
       return router.reduce((memo, current) => {
        memo[current.path] = current.component;
         retrun emo;  
      }, {})
    }
}

vueRouter.install = function(vue) {
  // 监听current变化
    vue.mixin({
      data: {
          beforeCreate: function() {     // $option new Vue({ router: [....] })的时候传入
          if(this.$options&&this.$options.$router) {
              this._root = this;               // 将当前组件的this给routerView
              this._router = this.$options.router;
            // 监听路由当前路径的变化
            vue.utils.defineReactive(this, 'current', this._router.history )
            }else{
              this._root = this.$parent._root;
            }
            Object.defineProporty(this, ''$router'',     { get()  { return this._root._router } })
          }
        }
  });
// 渲染控制
  vue.component('router-view',  {
    render(fn){
        let current = this._self._root._hitstory.current;
        let current = this._self._root._router.routerMap;
         return fn(routerMap[current]);
      }
  })
}

react-router的源码

Router的主体代码

class Router extends React.Component {
  static computeRootMatch(pathname) {
    return { path: "/", url: "/", params: {}, isExact: pathname === "/" };
  }

  constructor(props) {
    super(props);

    this.state = {
      location: props.history.location
    };

    this._isMounted = false; // 是否加载完全
    this._pendingLocation = null; // 加载中的路由路径
 
    if (!props.staticContext) { // 开启监听
      this.unlisten = props.history.listen(location => {
        if (this._isMounted) { // 加载完全后根据监听的location的改变
          this.setState({ location });
        } else {
          this._pendingLocation = location;
        }
      });
    }
  }

  componentDidMount() {
    this._isMounted = true;

    if (this._pendingLocation) {
      this.setState({ location: this._pendingLocation });
    }
  }

  componentWillUnmount() {
    if (this.unlisten) {  // 移除监听
      this.unlisten();
      this._isMounted = true;
      this._pendingLocation = null;
    }
  }

  render() {
    return (
      
        
      
    );
  }
}

向所有组件注入路由相关属性

import createContext from "mini-create-react-context";
// 与const {Provider, Consumer} = React.createContext(defaultValue); 效果一样
const createNamedContext = name => {
  const context = createContext();
  context.displayName = name;

  return context;
};

Route的实现

class Route extends React.Component {
  render() {
    return (
       // 注入route共有属性
        {context => {
          invariant(context, "You should not use  outside a ");

          const location = this.props.location || context.location;
          const match = this.props.computedMatch
            ? this.props.computedMatch //  already computed the match for us
            : this.props.path
            ? matchPath(location.pathname, this.props)
            : context.match;

          const props = { ...context, location, match };

          let { children, component, render } = this.props;

          // Preact uses an empty array as children by
          // default, so use null if that's the case.
          if (Array.isArray(children) && isEmptyChildren(children)) {
            children = null;
          }

          return (
             // 重新整理
              //   判断是否匹配是否有chidren根据类型渲染
              {props.match
                ? children
                  ? typeof children === "function"
                    ? __DEV__
                      ? evalChildrenDev(children, props, this.props.path)
                      : children(props)
                    : children
                  : component
                  ? React.createElement(component, props)
                  : render
                  ? render(props)
                  : null
                : typeof children === "function"
                ? __DEV__
                  ? evalChildrenDev(children, props, this.props.path)
                  : children(props)
                : null}
            
          );
        }}
      
    );
  }
}

你可能感兴趣的:(vue-router和react-router源码)