美文网首页
手写简单Vue-Router

手写简单Vue-Router

作者: Betterthanyougo | 来源:发表于2020-05-02 21:46 被阅读0次

vue-router

Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单⻚面应用变得易如反 掌。


image

安装: vue add router 核心步骤:
步骤一:使用vue-router插件,router.js
步骤二:创建Router实例,router.js export default new Router({...})
步骤三:在根组件上添加该实例,main.js

import router from './router'
new Vue({
  router,
}).$mount("#app");

步骤四:添加路由视图,App.vue

<router-view></router-view>

导航

 <router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>

vue-router源码实现

需求分析

作为一个插件存在:实现VueRouter类和install方法 实现两个全局组件:router-view用于显示匹配组件内容,router-link用于跳转 监控url变化:监听hashchange或popstate事件 响应最新url:创建一个响应式的属性current,当它改变时获取对应组件并显示

实现一个插件:创建VueRouter类和install方法

 
let Vue; // 引用构造函数,VueRouter中要使用
// 保存选项
class VueRouter {
  constructor(options) {
    this.$options = options;
} }
// 插件:实现install方法,注册$router VueRouter.install = function(_Vue) {
// 引用构造函数,VueRouter中要使用 Vue = _Vue;
// 任务1:挂载$router Vue.mixin({
beforeCreate() {
// 只有根组件拥有router选项
if (this.$options.router) {
        // vm.$router
        Vue.prototype.$router = this.$options.router;
      }
} });
// 任务2:实现两个全局组件router-link和router-view Vue.component('router-link', Link) Vue.component('router-view', View)
};
export default VueRouter;

为什么要用混入方式写?主要原因是use代码在前,Router实例创建在后,而install逻辑又需要用 到该实例

创建router-view和router-link

创建krouter-link.js

export default {
  props: {
to: String,
    required: true
  },
render(h) {
web全栈架构师
 
// return <a href={'#'+this.to}>{this.$slots.default}</a>;
    return h('a', {
      attrs: {
        href: '#' + this.to
      }
    }, [
      this.$slots.default
]) }
}

创建krouter-view.js

export default {
  render(h) {
// 暂时先不渲染任何内容
    return h(null);
  }
}

监控url变化

定义响应式的current属性,监听hashchange事件

 
class VueRouter {
  constructor(options) {
// current应该是响应式的 Vue.util.defineReactive(this, 'current', '/')
// 定义响应式的属性current
const initial = window.location.hash.slice(1) || '/' Vue.util.defineReactive(this, 'current', initial)
// 监听hashchange事件
window.addEventListener('hashchange', this.onHashChange.bind(this)) window.addEventListener('load', this.onHashChange.bind(this))
}
  onHashChange() {
    this.current = window.location.hash.slice(1)
} }

router-view

 
export default {
  render(h) {
// 动态获取对应组件
let component = null; this.$router.$options.routes.forEach(route => {
      if (route.path === this.$router.current) {
        component = route.component
} });
    return h(component);
  }
}

提前处理路由表

提前处理路由表避免每次都循环

 
class VueRouter {
  constructor(options) {
// 缓存path和route映射关系
this.routeMap = {} this.$options.routes.forEach(route => {
      this.routeMap[route.path] = route
    });
} }

router-view

 
export default {
  render(h) {
    const {routeMap, current} = this.$router
    const component = routeMap[current] ? routeMap[current].component : null;
    return h(component);
} }

完整代码

// 我们的插件:
// 1.实现一个Router类并挂载期实例
// 2.实现两个全局组件router-link和router-view
let Vue;

class VueRouter {
  // 核心任务:
  // 1.监听url变化
  constructor(options) {
    this.$options = options;

    // 缓存path和route映射关系
    // 这样找组件更快
    this.routeMap = {}
    this.$options.routes.forEach(route => {
      this.routeMap[route.path] = route
    })

    // 数据响应式
    // 定义一个响应式的current,则如果他变了,那么使用它的组件会rerender
    Vue.util.defineReactive(this, 'current', '')

    // 请确保onHashChange中this指向当前实例
    window.addEventListener('hashchange', this.onHashChange.bind(this))
    window.addEventListener('load', this.onHashChange.bind(this))
  }

  onHashChange() {
    // console.log(window.location.hash);
    this.current = window.location.hash.slice(1) || '/'
  }
}

// 插件需要实现install方法
// 接收一个参数,Vue构造函数,主要用于数据响应式
VueRouter.install = function (_Vue) {
  // 保存Vue构造函数在VueRouter中使用
  Vue = _Vue

  // 任务1:使用混入来做router挂载这件事情
  Vue.mixin({
    beforeCreate() {
      // 只有根实例才有router选项
      if (this.$options.router) {
        Vue.prototype.$router = this.$options.router
      }

    }
  })

  // 任务2:实现两个全局组件
  // router-link: 生成一个a标签,在url后面添加#
  // <a href="#/about">aaaa</a>
  // <router-link to="/about">aaa</router-link>
  Vue.component('router-link', {
    props: {
      to: {
        type: String,
        required: true
      },
    },
    render(h) {
      // h(tag, props, children)
      return h('a',
        { attrs: { href: '#' + this.to } },
        this.$slots.default
      )
      // 使用jsx
      // return <a href={'#'+this.to}>{this.$slots.default}</a>
    }
  })
  Vue.component('router-view', {
    render(h) {
      // 根据current获取组件并render
      // current怎么获取?
      // console.log('render',this.$router.current);
      // 获取要渲染的组件
      let component = null
      const { routeMap, current } = this.$router
      if (routeMap[current]) {
        component = routeMap[current].component
      }
      return h(component)
    }
  })
}

export default VueRouter

相关文章

  • 手写简单Vue-Router

    vue-router Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成...

  • 2-9 vue-router

    vue-router vue-router 用 Vue.js + vue-router 创建单页应用,是非常简单的...

  • vue-router

    vue-router简单配置

  • 手写vue-router

    一、准备工作 所以,上面的new Router()就是我们要实现的。 二、实现Router 根据上面的代码,可以看...

  • 手写vue-router

    今天刚好有时间,最近也在观察vue3新特性,抽空玩一玩嵌套路由的vue-router,直接上代码 项目目录结构 代...

  • 手写VueRouter简单实现hash路由

    vue-router用法 首先简单看看vue-router简单用法: 从上面代码可以看到,在route.js中导出...

  • 【前端】Vue-router

    一、简单介绍 vue-router是vue官方的路由解决方案,简单易用,中文官方地址如下:vue-router中文...

  • 手写vue-router源码

    ## 测试

  • vue2.0 vue-router

    vue-router 用 Vue.js + vue-router 创建单页应用,是非常简单的。使用 Vue.js ...

  • vue-router 配置路由

    vue-router 配置路由 用 Vue.js + vue-router 创建单页应用,是非常简单的。使用 Vu...

网友评论

      本文标题:手写简单Vue-Router

      本文链接:https://www.haomeiwen.com/subject/rpmlghtx.html