Vue深入学习之手写一个简单的Vuerouter

参照vue-router的使用方法
// 0. 如果使用模块化机制编程,导入Vue和VueRouter,要调用 Vue.use(VueRouter)

import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)

// 1. 定义 (路由) 组件。
// 可以从其他文件 import 进来
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }

// 2. 定义路由
// 每个路由应该映射一个组件。 其中"component" 可以是
// 通过 Vue.extend() 创建的组件构造器,
// 或者,只是一个组件配置对象。
// 我们晚点再讨论嵌套路由。
const routes = [
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
]

// 3. 创建 router 实例,然后传 `routes` 配置
const router = new VueRouter({
  routes // (缩写) 相当于 routes: routes
})

// 4. 创建和挂载根实例。
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
const app = new Vue({
  router
}).$mount('#app')

使用


<div id="app">
  <h1>Hello App!</h1>
  <p>
    <!-- 使用 router-link 组件来导航. -->
    <!-- 通过传入 `to` 属性指定链接. -->
    <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
    <router-link to="/foo">Go to Foo</router-link>
    <router-link to="/bar">Go to Bar</router-link>
  </p>
  <!-- 路由出口 -->
  <!-- 路由匹配到的组件将渲染在这里 -->
  <router-view></router-view>
</div>
分析

vue.use() //说明 vue-router 插件中有install 方法
使用时候 有 routerLink 和routerView组件,routerLink组件根据传入 to 属性指定不同链接,引入不同的组件,将组件渲染再routerView所在的位置。
根据hash地址的变化渲染不同的组件。

实现

步骤.调用install方法的时候,如果是根组件包含router信息,
1.进行初始化routerLink,routerView两个组件,
2.设置路由path和组件的映射关系routerMap,
3.监听路由的变化事件。
初始化组件:
routerLink接受一个props和一个slot转换成A标签
routerView组件根据path的变化,从routerMap中取相应的组件信息,进行渲染(需要是响应式的)将对应的组件渲染再router–view的区域。
初始化sourceMap:
根据实例初始化时的routes参数,转化为path和component的映射关系
初始化事件:
事件监听,监听hashchange和load事件更改当前的路径(hash模式)。
路由守卫 :
hashchange时候根据e(事件对象),获取 from,to,执行next()时候进行改变hash
实例方法:
全局push方法: 在install将就$router 挂载全局,push时候 改变当前路径。

代码实现
let Vue   // 为什么不import?
export default class Svuerouter {
  constructor(options) {
    this.$options = options;
    this.routerMap={}
    //Vue.observable方法将数据设置为响应式,让render函数动态的渲染(new Vue也可以,vue.util.defineReactive方法也可以,$set()应该也可以)
    //方法一
    // _vue.util.defineReactive(
		// 	this,"current","/about"
		// )
    this.vm = Vue.observable({  
      current:location.hash.slice(1)||'/'
    })
  }
  static install(_vue, option) {
    Vue = _vue;
    //全局混入生命周期,让插件初始化的时候获取到路由的相关参数
    Vue.mixin({
      beforeCreate() {
        if (this.$options.router) {
          this.$options.router.init();
          Vue.prototype.$router = this.$options.router
        }
      },
    })
  }
  init() {
    this.initcomponents()
    this.initrouter()
    this.initevent()
  }
  initcomponents() {
    //初始化router-link组件,为什么不用template?可以使用jsx,建议使用render函数(注意当前this的指向)
    Vue.component("router-link", {
      props: {
        to: {
          type: String,
          require: true
        }
      },
      render(h) { 
        // return <a href={`#${this.to}`}>{this.$slots.default}</a>
        return h("a", {
          attrs: {
            href: `#${this.to}`
          }
        }, [this.$slots.default])
      }
    });
    // 渲染对应的路由组件(注意当前this的指向)
    Vue.component("router-view",{
      render:(h)=>{
        let component = this.routerMap[this.vm.current].component||null
        return h(component)
      }
    })
  }
  //初始化组件path和组件对象的映射关系
  initrouter() {
    this.$options.routes.forEach((item)=>{
      this.routerMap[item.path]=item
    })
  }
  initevent() {
    window.addEventListener("hashchange",this.getcurrent.bind(this))
    window.addEventListener("onload",this.getcurrent.bind(this))
  }
  getrouterLife(e){
    let from,to;
    if(e.type == "hashchange"){
      from = e.oldURL.split("#")[1];
      to = e.newURL.split("#")[1];
    }else{
      from = '';
      to = location.hash.slice(1);
    }
    return {
      from,
      to
    }
  }
  //判断是否有路由守卫
  getcurrent(e){
    if(this.routerMap[this.vm.current].beforeRouterEnter){
      let {from,to} = this.getrouterLife(e)
      this.routerMap[this.vm.current].beforeRouterEnter(from,to,()=>{
        this.vm.current = location.hash.slice(1);
      })
    }else{
      this.vm.current = location.hash.slice(1);
    }
  }
  //添加Vuerouter实例的方法
  push(path){
    this.vm.current = path
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值