基于 Vue 实现简易 Vue-Router

简介: 基于 Vue 实现简易 Vue-Router

image.png


一、简介

在日常开发中,无论使用 Vue 还是 React ,都会不可避免的使用到与其最相配的路由管理器 Vue-Router 或 React-Router. 作为前端开发的诸君相信对于路由原理也有所了解,也不妨实现一个自己的路由,加深理解.

二、准备工作

1. 这里为了方便,使用 vue-cli 创建了一个项目,目录结构如下:

image.png

2. 首先观察 vue-router 是如何使用的,主要涉及到 main.js 和 router文件夹下的 index.js

main.js 中就是简单的引入,将 router 加入到 new Vue 的 options 中.

image.png

router/index.js 这里都是常规的内容,不在做过多解释.

image.png

三、路由原理

1. 前端路由分为 hash 路由 和 history 路由

  • hash 模式是根据 url 上 #/ 部分的变化来对应页面的展示,同时不会刷新页面,也就是不会自动重新向服务器发送请求,除了代码中的请求,一般是通过 js 来对页面进行渲染
  • history 则是根据页面 url 的变更对应页面上的内容,准确的说是会自动向服务器请求对应页面的文件资源,然后在浏览器上进行加载渲染

2. 实现前端路由的关键点

  • 如何改变 URL 时却不引起页面刷新?
  • 如何监听 URL 的变化?

Hash 模式

  • hash 是 URL 中 hash (#) 及后面的那部分,常用作锚点在页面内进行导航,改变 URL 中的 hash 部分不会引起页面刷新
  • 通过 window.onhashchange 事件监听 URL 的变化. URL 发生变化的场景有:
  • 通过浏览器前进后退
  • 通过<a>标签
  • 通过 window.location
  • 以上情况改变 URL 都会触发 hashchange 事件

History 模式

  • HTML5 中为 history 提供了 pushState 和 replaceState 新接口,这两个方法改变 URL 的 path 部分不会引起页面刷新
  • history 提供类似 hashchange 事件的 popstate 事件,但 popstate 事件有些不同:
  • 通过浏览器前进后退改变 URL 时会触发 popstate 事件,通过pushState/replaceState或 <a> 标签改变 URL 不会触发 popstate 事件
  • 但可以通过拦截 pushState/replaceState 的调用和 <a> 标签的点击事件来检测 URL 变化,也可实现监听 URL 的变化
  • 四、实现 MyRouter
    这里 MyRouter 主要实现 hash 模式,知道了路由原理, history 模式也是同样的,同样的即便需要基于 Vue3 实现也是一样的原理,只是实现上会有些差异, 这里就不过多描述.
    1. 定义 MyRouter 类,主要内容有
  • 保存外界路由数据
  • 监听路由变化
  • 将当前路由地址存储在响应式数据中,响应式数据通过 Vue.util.defineReactive 实现
  • 2. MyRouter.install 方法,主要是通过在 Vue.use 的时候进行调用
  • 通过 mixin 为所有组件混入只读的路由信息,同时指定所有组件的根组件 _root 指向同一个实例
  • 全局注册 router-link
  • 全局注册 router-view,同时根据 Vue.protype.$router 上的信息渲染对应的路由视图内容
  • 3. 使用方式几乎没有变化,和 vue-router 保持了一致性
    image.png
    4. 完整代码如下
import Vue from 'vue';
export default class MyRouter {
constructor(config) {
  // 保存路由数据
  this.routers = config.routes;
  // 保存转换后的路由信息
  this.routersMap = this.getRoutersMap(config.routes);
  // 转换为响应式数据,保存当前路由路径
  Vue.util.defineReactive(this, 'currentPath', '');
  // 初始化
  this.initRouter();
}
initRouter() {
  // 1.初始化获取当前页面地址
  this.getCurrentPath();
  // 2.监听路由地址变化
  window.onhashchange = () => {
    this.getCurrentPath();
  };
}
// 获取 { [path]: [component] } 形式的路由数据
getRoutersMap(routes) {
  return routes.reduce((memo, curr) => {
    memo[curr.path] = curr.component;
    return memo;
  }, {});
}
// 获取当前页面地址
getCurrentPath() {
  this.currentPath = window.location.hash.slice(1) || '/';
}
}
// Vue.use 时执行
MyRouter.install = function (Vue) {
// 在 Vue 原型挂载 $router,使用 mixin 延迟到组件构建之后执行, 否则获取不到 this.$options
Vue.mixin({
  created() {
    // 只有在 this.$options.router 存在时赋值给 $router,此时 this 代表的是根组件,因为根组件才含有 router 选项
    if (this.$options.router) {
      this._root = this;
      Vue.prototype.$router = this.$options.router;
      // 保证 $router 不能被修改
      Object.defineProperty(Vue.prototype, '$router', {
        writable: false
      });
    } else {
      // 让所有的子组件都指向共同的根组件实例
      this._root = this.$parent._root;
    }
  }
});
// 注册 router-link
Vue.component("router-link", {
  props: {
    "to": String
  },
  // template: `<a :href="to" class="my-router-link"><slot></slot></a>`,
  render(h) {
    return h('a', {
      attrs: {
        href: `#${this.to}`,
      },
      class: "my-router-link",
    }, this.$slots.default)
  },
});
// 注册 router-view
Vue.component("router-view", {
  render(h) {
    if (this.$router) {
      return h(this.$router.routersMap[this.$router.currentPath]);
    } else {
      return null;
    }
  }
});
};


目录
相关文章
|
5天前
|
JavaScript 前端开发
【vue】iview如何把input输入框和点击输入框之后的边框去掉
【vue】iview如何把input输入框和点击输入框之后的边框去掉
12 0
|
6天前
|
资源调度 JavaScript 前端开发
Vue的路由管理:VueRouter的配置和使用
【4月更文挑战第24天】VueRouter是Vue.js的官方路由管理器,用于在单页面应用中管理URL路径与组件的映射。通过安装并引入VueRouter,设置路由规则和创建router实例,可以实现不同路径下显示不同组件。主要组件包括:`&lt;router-link&gt;`用于创建导航链接,`&lt;router-view&gt;`负责渲染当前路由对应的组件。此外,VueRouter还支持编程式导航和各种高级特性,如嵌套路由、路由参数和守卫,以应对复杂路由场景。
|
4天前
|
监控 JavaScript
Vue中的数据变化监控与响应——深入理解Watchers
Vue中的数据变化监控与响应——深入理解Watchers
|
4天前
|
JavaScript 安全 前端开发
Vue 项目中的权限管理:让页面也学会说“你无权访问!
Vue 项目中的权限管理:让页面也学会说“你无权访问!
13 3
|
4天前
|
JavaScript 前端开发 开发者
Vue的神奇解锁:冒险的开始
Vue的神奇解锁:冒险的开始
5 1
|
5天前
|
JavaScript
【vue实战】父子组件互相传值
【vue实战】父子组件互相传值
10 1
|
5天前
|
JavaScript
vue2_引入Ant design vue
vue2_引入Ant design vue
9 0
|
5天前
|
JavaScript
vue知识点
vue知识点
13 4
|
5天前
|
存储 JavaScript 前端开发
【Vue】绝了!这生命周期流程真...
【Vue】绝了!这生命周期流程真...
|
6天前
|
JavaScript 索引
【vue】框架搭建
【vue】框架搭建
8 1