我们在使用vue-router时不免有如下的疑问:

1. 这个router插件内部到底实现了什么,才使得页面跳转无刷新?

2. 为什么要把router实例加入到Vue配置项中?

3. 为什么使用<router-view><router-link>等不需要注册?

4. 为什么我点了<router-link><router-view>的内容能正常切换?

5. 为什么this.$router.push能改变url地址?

 

那么带着问题,希望你通读全文,我想你会找到想要的答案的(假装这些问题都是你问的~)

 

我们知道,每次我们在做vue项目时需要使用router时:

1.首先都会在路由文件的index.js文件中声明:

 

Vue.use(VueRouter)  //使用VueRouter这个插件

2.接着我们需要在index.js中创建一个实例:

const router = new VueRouter({

  mode: 'hash',

  base: process.env.BASE_URL,

  routes

})

  

3. 接下来我们在main.js中把这个router实例放入到Vue实例中:

new Vue({

  el: '#app',

  router,//在Vue实例中放入这个router实例

  components: { App },

  store,

  template: '<App/>'

})

接着我们就可以用了,ok全文结束,goodbye!我去弹我的尤克里里去了~

 

(读者:做咩野啊~?)

 

(呃额呃呃别打了哥,疼疼疼,我说我说我都说,今天不给各位讲的明明白白我不走了好吧)

 停止闲扯,重点来了:

  我们仔细想想,我们如果要自制一个router,那需要实现些什么?首先vue-router是通过Vue.use引入的,说明它是一个插件,这个插件内肯定实现了router-viewrouter-link两个组件的编译模板我们先配置好一个自己的router文件,如下:

 

main.js中引入

import router from './myRouter'

myRouter文件中的index.js添加

import VueRouter from './myvue-router'

做好前置工作,接下来,我们就来开发一个插件,首先翻看vue文档,发现对开发插件有着详尽的说明:

 

第一个参数是一个Vue,在复杂的数据流中我们就需要通过像that=this一样把这个宝贵的Vue保存起来,同时防止打包时把vue实例打包进插件里面,接下来我们要用到mixin的全局引入,老规矩,先看文档:

再观察我们的Vue实例配置:

new Vue({

  router,

  store,

  render: h => h(App)

}).$mount('#app')

可见,我们可以通过this.$options.router访问到Vue实例中的router,那么,如果这个选项存在,那么我们就可以在vue原型上挂载一个$router选项,那么我们就能通过this.$router访问到vuerouter实例了,是不是很妙!

但别忘了在install中还有重要的一步就是实现router-linkrouter-viewrouter-link实际上是一个不发生跳转的超链接,即它的href’#’拼接上router-link标签中的to的值,我们把to放入props中传给这个component即可实现组装render出一个点击可跳转的链接,但是router-link中的名称怎么渲染呢?唉~同学你忘了作用域插槽啦,通过this.$slots.default访问到这个标签的默认内容,我的router-link中想写什么就写什么,不怕render不出来哈哈。

至于router-view,可能稍微有些复杂。大家想,为什么我们点击router-link链接能自动将router-view内的内容自动更新?一定是router-view中有某种获取url改变的神奇方法,并将改变后的路由的配置对象与routes中现存的路径进行匹配,将匹配成功的配置对象追加到渲染的组件上,那么我们就可以通过一个响应式的变量current来存储这个目前选中的路径值(用Vue.util.defineReactive来实现响应式),再在整个$options配置项中的路由项中查找是否有相同的路径值,将这个匹配成功的routecomponent配置renderreturn出去。至此一个不支持嵌套子路由但支持主路由的router源码就实现啦(嵌套子路由后面再实现)具体源码如下:

 

//目标:

//1.实现插件

//2.两个组件

// vue插件:function 必须有一个install,会被Vue.use调用

let Vue //保存Vue构造函数,插件中使用

class VueRouter {

  constructor(options) {

    //保存当前选项

    this.$options = options

    //current是 vuerouter的一个实例属性

    const initial = window.location.hash.slice('#') || '/';//因route中的配置对象都为'/Home'的形式,而此时的window.location.hash为'#/Home'的形式,所以需要截掉#

    // //Vue插件开发一系列api,目的是实现数据响应式,即将router-view中依赖于current的数据在current发生变化时也重新渲染

    Vue.util.defineReactive(this, 'current', initial)

    // 监听hash变化

    window.addEventListener('hashchange', () => {

      this.current = window.location.hash.slice(1)//截取#后的内容

    })

  }

}

//_Vue是Vue.use调用时传入的

VueRouter.install = function (_Vue) {

  // 保存一下输入,同时防止打包时把vue实例打包进插件里

  Vue = _Vue

  // 通过全局混入,延迟下面的逻辑到router创建完毕并且附加到选项上才执行

  Vue.mixin({

    created () {

      //此钩子在每个组件创建实例时都会调用,根实例才有此选项

      if (this.$options.router) {//this.$options指new Vue时的选项

        Vue.prototype.$router = this.$options.router

      }

    }

  })

  // 2.注册实现两个组件router-view,router-link

  Vue.component('router-link', {

    props: {

      // 拿到router-link中的to属性

      to: {

        type: String,

        required: true

      },

    },

render (h) {

      // 拿到当前的hash地址,传给href

      return <a href={'#' + this.to}>{this.$slots.default}</a>

    }

  })

  Vue.component('router-view', {

    // 渲染函数

    render (h) {

      // 先设置一个component

      let component = null

      const route = this.$router.$options.routes.find(

        // 拿出上面计算得出的current来匹配route选项

        (route) => route.path === this.$router.current

      )

      if (route) {

        // 使component获取组件配置对象

        component = route.component

      }

      // 返回该component的虚拟dom

      return h(component)

    }

  })

 

}

export default VueRouter

实现效果:

引入的是myRouter文件里的router哈:

 

 效果如下:

 

 

 

 

至此一个简易的vue-router源码就实现啦~作为一个21岁的前端小白,大四在读实习生,如果有写得不对的地方还望各位能不吝赐教,小生定当俯首恭听,感恩戴德~

 

附加提醒:

1. routes是什么:

 

2. 路由的router-linkrouter-view使用方式提示:

 

3. $optins是什么?

 

就是这个new Vue{}里面的内容

内容来源于网络如有侵权请私信删除

文章来源: 博客园

原文链接: https://www.cnblogs.com/funkyou/p/14580129.html)

你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!

相关课程