当前位置: 首页 > article >正文

基于 Vue 实现简易 Vue-Router

一、简介

在日常开发中,无论使用 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;
    }
  }
});
};


http://www.kler.cn/a/396494.html

相关文章:

  • C/C++静态库引用过程中出现符号未定义的处理方式
  • react 中 memo 模块作用
  • 【知识科普】微内核架构与宏内核架构
  • 栈相关算法题1|通过栈判断链表是否对称|共享栈入栈出栈|括号匹配|多种括号配对|递归求序列最大值(C)
  • 【Zabbix自动化运维监控系列】判断zabbix是主动监控,还是被动监控
  • 【服务器】本地安装X11 服务器-Windows
  • GESP4级考试语法知识(贪心算法(五))
  • [白月黑羽]关于仿写类postman功能软件题目的解答
  • Leetcode 每日一题 125.验证回文串
  • PLC如何支持GEM300标准?SECS/GEM通讯协议
  • 卷积层(CNN)全面解析
  • 如何使用 python 中的 Pillow 创建可自定义的图标生成器
  • 软件工程视角:Git 基础与实践
  • NLP开发常见问题
  • 微信小程序之路由跳转传数据及接收
  • JWTUtil工具类
  • 加深深度学习矩阵计算理解--用人类直觉 走进线性代数(非应试)
  • 自存 关于RestController请求传参数 前端和后端相关
  • web——upload-labs——第五关——大小写绕过绕过
  • HarmonyOS本地存储-Preferences(用户首选项)的使用
  • MATLAB 使用教程 —— 常用函数
  • Git 时想要放弃当前的 commit 操作
  • Javaweb-day11案例(文件)
  • 基于stm32的智能变频电冰箱系统
  • 网络安全练习之 ctfshow_web
  • 力扣 LeetCode 232. 用栈实现队列(Day5:栈与队列)