实现vue-router部分功能

目的

为了了解路由的底层工作原理,自己参考资料,仿写了vue-router的部分功能。当然自己写的DEMO功能较粗糙,主要实现核心功能,其它功能有待完善、补充。

 

思路

参考vue-router,我们实现路由插件的api、组件尽量保持跟vue-router一样;

 

首先添加一个SRouter类,来模拟vue-router插件的功能,暂且不管类的实现;

提供router.js文件,然后new SRouter(options),options传递的就是所有的组件路径以及路由访问路径,结构同使用vue-router,只是new的对象不一样,我们new的是自己实现的路由类;

接着来实现SRouter类,主要包括以下几步:
a. 首先在类中提供静态的intall函数,方便Vue.use调用,在里面来调用路由的初始化函数
b. 注册router-link、router-view组件
c. 监听hashchange事件,获取路由对应的组件,router-view装载对应的组件
d. 处理钩子函数
实现以上几步,可以满足路由的基本功能。

 

品牌vi设计公司http://www.maiqicn.com 办公资源网站大全https://www.wode007.com

实现

主要贴出部分关键代码,具体可以参考源码地址

1. SRouter类:

a. 首先在类中提供静态的intall函数,方便Vue.use调用,在里面来调用路由的初始化函数
主要解释下intall里面为什么使用mixin,这是为了在创建vue实例后调用我们的路由初始化工作;然后constructor中使用new Vue()主要是为了使用vue的数据响应式,能自动检测到数据的变化;

   static install(_vue) {
       Vue = _vue
       Vue.mixin({
           beforeCreate() {
               //这里的router就是我们在new Vue的时候传递的router对象
               if (this.$options.router) {
                   Vue.prototype.$srouter = this.$options.router
                   this.$options.router.init()
               }
           }
       })
   }

   constructor(opitons) {
       this.$options = opitons
       this.routeMap = {}
       this.app = new Vue({
           data: {
               current: '/'
           }
       })
   }

   //路由初始化函数
   init() {
       //启动路由
       //1.初始化组件router-link router-view
       this.initComponent()
       //2.监听hashchange事件
       this.handleEvents()
       //3.处理路由
       this.createRouterMap()
       //3.处理钩子函数
   }

b. 注册router-link、router-view组件

    //初始化组件 router-view router-link
   initComponent() {
       Vue.component('router-view', {
           render: h => {
               const component = this.routeMap[this.app.current].component
               //使用h新建一个虚拟dom
               return h(component)
           }
       })
       Vue.component('router-link', {
           props: {
               to: String
           },
           render(h) {
               return h('a', {
                       attrs: {
                           href: '#' + this.to
                       }
                   },
                   [this.$slots.default]
               )
           }
       })
   }

c. 监听hashchange事件,获取路由对应的组件,router-view装载对应的组件

    //注册监听事件
   handleEvents() {
       window.addEventListener('hashchange', this.onHashChange.bind(this), false)
       window.addEventListener('load', this.onHashChange.bind(this), false)
   }

   //监听hash改变
   onHashChange(e) {
       //路由跳转
       let hash = window.location.hash.slice(1) || '/'
       let router = this.routeMap[hash]
       if (router && router.beforeEnter) {
           let [from, to] = [e.oldURL?.split('#')[1], e.newURL?.split('#')[1] || '/']
           router.beforeEnter(from, to, () => {
               this.app.current = hash
           })
       } else {
           this.app.current = hash
       }
   }

2. router.js文件,基本完全同vue-router的router.js文件,只是我们引入的是SRouter对象;

import Vue from 'vue'
import SRouter from './s-router'
Vue.use(SRouter)
export default new SRouter({
   routes: [
       {
           name: 'index',
           path: '/',
           component: () => import('./views/index'),
           beforeEnter(from, to, next) {
               //处理异步请求
               setTimeout(()=>{
                   next()
               })
           }
       }, {
           name: 'about',
           path: '/about',
           component: () => import('./views/about')
       }
   ]
})
posted @ 2020-09-20 14:31  笑人  阅读(160)  评论(0编辑  收藏  举报