Vue React源码看这真香系列之vue-router完整版复制即可

本文章主要用于本人观看

// 报错Cannot call a class as a function:用class不行,所以得换成函数
// class myRouter {
//   constructor(){
//     console.log(1)
//   }
// }
/* 
  我们需要一个路由状态,需要通过这个状态的变化更改组件。
  当hash变化会触发onhashchange去改变这个路由状态,defineProperty去监控这个路由状态
*/
class History{
  constructor(){
    /* 
      current就是路由的状态{current:'/home'},当这个状态变化的时候,会触发defineProperty,
      拿到current的状态值,改变组件 
    */
    this.current = null
  }
}
function MyRouter(opt){
  // 脚手架一上来就会运行一次,都挂好后再运行一次,运行两次
  console.log(this) // this第一次没有
  if(this){
    // console.log(opt)
    // 默认hash,
    this.mode = opt.mode || 'hash';
    this.routes = opt.routes || [];
    this.routeMap = this.createMap(this.routes)
    // 把路由状态挂载出来
    this.history = new History
    // 初始化路由
    this.init()
    console.log(this.routeMap)
  }
}
// 当给prototype赋址一个对象时必须要手动改变this指向
MyRouter.prototype = {
  // 改变this指向
  constructor:MyRouter,
  createMap(routes){ // routes数组拉平,拉成一个对象,直接用数组也可以
    return routes.reduce((prev,next) => {
      prev[next.path] = next.component
      return prev
    },{})
  },
  init(){
    // 初始化路由的时候看看mode是什么,走什么路由
    if(this.mode === 'hash'){ // hash路由
      // 没有hash就走/
      if(!location.hash)location.hash = '/'
      // 一开始就
      window.addEventListener('load',() => {
        // console.log('load')
        this.history.current = location.hash.slice(1)
        console.log(this.history.current)
      })
      // 当hash发生变化的时候改变current值
      window.addEventListener('hashchange',() => {
        this.history.current = location.hash.slice(1)
        console.log(this.history.current)
      })
    }else if(this.mode === 'history'){ // history路由
      // 没有pathname就走/
      if(!location.pathname)location.hash = '/'
      window.addEventListener('load',() => {
        this.history.current = location.pathname
        console.log(this.history.current)
      })
      // 当hash发生变化的时候改变current值
      window.addEventListener('popstate',() => {
        this.history.current = location.pathname
      })
    }
  },
  push(path){
    if(this.mode === 'hash'){
      location.hash = '#' + path
    }else  if(this.mode === 'history'){
      location.pathname = path
    }
  }
}

// 只要是用了Vue.use(xxx),就会调用xxx.install方法,就能拿到方法,并且再use的时候会把Vue的实例当作参数传进来
MyRouter.install = function(Vue){
  console.log(this)
  // 每个组件都能拿到mixin里的内容
  Vue.mixin({
    beforeCreate () {
      // console.log('beforeCreate')
      /* 
        这里的this代表每个组件
        $options;可以看到所有vue实例上的所有的自定义的属性
        在main.js中可以看到new Vue上挂了一个router的属性
      */
      console.log(this)
      // this.$options.router 组件的$options的身上有router的属性说明是根组件
      // 让每个组件都能拿到MyRoute的实例,用来拿到MyRoute上的属性和方法
      if(this.$options && this.$options.router){ // 根组件
        console.log(this)
        this._root = this;
        this._router = this.$options.router
        //深度监听current
        Vue.util.defineReactive(this,'xxx',this._router.history)
        console.log(this._router)
      }else{ // 不是根组件,是子组件
        // console.log(this.$parent)
        if(this.$parent){
          this._root = this.$parent._root //  this._root = this.$parent._root
          this._router = this.$parent._router
          console.log(this._router)
        }
       
      }
      // 用definePrototype给每一个组件添加一个$route和$router的属性
      Object.defineProperty(this,'$route',{
        get:() => {
          console.log(this._router.history)
          return {
            current:this._router.history.current
          }
        }
      })
      Object.defineProperty(this,'$router',{ // defineProperty
        get:() => {
          console.log(this._router)
          return this._router
        }
      })
    }
  })



  Vue.component('router-view',{
    render(h){
      console.log(this)
      const {routeMap,history:{current}} = this._self._router
      console.log(this._self._router.history)
      return h(
        routeMap[current]
      )
    }
  })

  Vue.component('router-link',{
    props:['to','tag'],
    methods: {
      click(ev,mode){
        console.log(ev)
        if(mode === 'hash'){
          location.hash = ev.target.getAttribute('href').split('#')[1];
        }else if(mode === 'history'){
          location.pathname = ev.target.getAttribute('href')
        }
      }
    },
    render(){
      const {mode} = this._self._router
      const {to} = this
      // console.log(this)
      // 默认插槽就是内容
      // console.log(this.tag)
      if(this.tag){
        return <this.tag on-click={(ev) => {this.click(ev,mode)}} href={mode === 'hash'?`#${to}`:to}>{this.$slots.default}</this.tag>
      }
      return <a href={mode === 'hash'?`#${to}`:to}>{this.$slots.default}</a>
    }
  })
}
export default MyRouter
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 你怎么不复读呢? 我们总是在做出选择了之后感觉到后悔,一路走来,有好多好多遗憾,那些遗憾和后悔都让我们觉得我们失去...
    旧轩里阅读 3,290评论 4 2
  • 最亲爱的你 想变成最美的风景,只为能看到你久违的笑容; 想变成一台单反,记录你每一次快乐的...
    炎心尘阅读 968评论 0 0
  • 在一阵慌乱的内心中醒来醒来,又做梦啦!又做梦啦! 她进入了我的梦里,慌乱的心房因为她而慌张的乱跳乱跳,心里,有,不...
    窗前的小豆豆Y阅读 1,504评论 6 5
  • 有一句话很流行:好好珍惜对你好的人,弄丢了,上百度也找不回来了…… 人生在世,该爱则爱,该恨则恨。几十年后,一人一...
    一抹晨曦_e23f阅读 1,454评论 0 1

友情链接更多精彩内容