vue-router 源码:前端路由

2023-11-13

前言

在学习 vue-router 的代码之前,先来简单了解一下前端路由。

前端路由主要有两种实现方法:

  1. Hash 路由
  2. History 路由

先来看看这两种方法的实现原理。

接着我们将用它们来简单实现一个自己的前端路由。

前端路由

Hash 路由

url 的 hash 是以 # 开头,原本是用来作为锚点,从而定位到页面的特定区域。当 hash 改变时,页面不会因此刷新,浏览器也不会向服务器发送请求。

http://www.xxx.com/#/home
复制代码

同时,hash 改变时,并会触发相应的 hashchange 事件。所以,hash 很适合被用来做前端路由。当 hash 路由发生了跳转,便会触发 hashchange 回调,回调里可以实现页面更新的操作,从而达到跳转页面的效果。

window.addEventListener('hashchange', function () {
  console.log('render');
});
复制代码

History 路由

HTML5 规范中提供了 history.pushStatehistory.replaceState 来进行路由控制。通过这两个方法,可以实现改变 url 且不向服务器发送请求。同时不会像 hash 有一个 #,更加的美观。但是 History 路由需要服务器的支持,并且需将所有的路由重定向到根页面。

History 路由的改变不会去触发某个事件,所以我们需要去考虑如何触发路由更新后的回调。

有以下两种方式会改变 url:

  1. 调用 history.pushState 或 history.replaceState;
  2. 点击浏览器的前进与后退。

第一个方式可以封装一个方法,在调用 pushState(replaceState)后再调用回调。

function push (url) {
  window.history.pushState({}, null, url);
  handleHref();
}

function handleHref () {
  console.log('render');
}
复制代码

第二个方式,浏览器的前进与后退会触发 popstate 事件。

window.addEventListener('popstate', handleHref);
复制代码

路由实现

我们通过 <a> 标签来进行切换路由,通过一个 <div> 标签来装载各路由对应的页面内容。

参考 vue-router 的调用,我们会这么地调用一个 Router,将路由与对应组件作为参数传入:

const router = new Router([
  {
    path: '/',
    component: 'home'
  },
  {
    path: '/book',
    component: 'book'
  },
  {
    path: '/movie',
    component: 'movie'
  }
]);
复制代码

数组里是各路由对应的要显示的内容,接下来就来开始实现这个 Router

Hash 路由实现

Hash 路由 <a> 标签都需要带上 #

<div>
  <a href="#/">home</a>
  <a href="#/book">book</a>
  <a href="#/movie">movie</a>
    
  <div id="content"></div>
</div>
复制代码

Router 的代码实现如下:

class Router {
  constructor (options) {
    this.routes = {};
    
    this.init();
    
    // 遍历,绑定视图更新
    options.forEach(item => {
      this.route(item.path, () => {
      	document.getElementById('content').innerHTML = item.component;
      });
    });
  }
  
  // 绑定监听事件
  init () {
    window.addEventListener('load', this.updateView.bind(this), false);
    window.addEventListener('hashchange', this.updateView.bind(this), false);
  }
  
  // 更新试图
  updateView () {
    const currentUrl = window.location.hash.slice(1) || '/';
    this.routes[currentUrl] && this.routes[currentUrl]();
  }
  
  // 将路由与回调函数关联
  route (path, cb) {
    this.routes[path] = cb;
  }
}
复制代码

实现效果如下:

History 路由实现

History 路由需要服务器的支持,可以点击 这里 的代码参考。

<div>
  <a href="javascript:void(0);" data-href="/">home</a>
  <a href="javascript:void(0);" data-href="/book">book</a>
  <a href="javascript:void(0);" data-href="/movie">movie</a>
    
  <div id="content"></div>
</div>
复制代码

Router 的代码实现如下:

class Router {
  constructor (options) {
    this.routes = {};

    this.init();
    this.bindEvent();

    // 遍历,绑定视图更新
    options.forEach(item => {
      this.route(item.path, () => {
        document.getElementById('content').innerHTML = item.component;
      });
    });
  }

  // 绑定点击事件
  bindEvent () {
    const _this = this;
    const links = document.getElementsByTagName('a');

    [].forEach.call(links, link => {
      link.addEventListener('click', function () {
        const url = this.getAttribute('data-href');
        _this.push(url);
      });
    });
  }

  // 绑定监听事件
  init () {
    window.addEventListener('load', this.updateView.bind(this), false);
    window.addEventListener('popstate', this.updateView.bind(this), false);
  }

  push (url) {
    window.history.pushState({}, null, url);
    this.updateView();
  }

  // 更新试图
  updateView () {
    const currentUrl = window.location.pathname || '/';
    this.routes[currentUrl] && this.routes[currentUrl]();
  }

  // 将路由与回调函数关联
  route (path, cb) {
    this.routes[path] = cb;
  }
}
复制代码

实现效果如下:

最后

前端路由实现方式有两种,分别是:

  1. Hash 路由
  2. History 路由

原理都是修改 url 的同时不刷新页面,不向服务器发送请求,通过监听特殊的事件来更新页面。

以上实现全部源码参考 这里

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vue-router 源码:前端路由 的相关文章

  • angularjs:如何向资源对象添加缓存?

    在 http 中添加缓存非常简单 通过传递cache true http docs angularjs org api ng http https docs angularjs org api ng service 24http有缓存选项
  • 我如何在 AngularJS 中监听点击并按住的情况?

    我制作了一个时间计数器 您可以通过单击按钮来增加或减少时间 然而 我希望当我单击并按住按钮时 时间的价值会不断攀升 所以目前如果你看到我的Plunkr http plnkr co edit BxX9x5zYFMXVqt5JsN1F p pr
  • chrome 调试器承诺在暂停时不会解析?

    也许我没有正确调试承诺 但基本上 如果您在断点处停止并运行异步代码 它实际上不会完成 直到您恢复执行为止 这是一个问题 调试器允许您快速试验多个 api 方法 但如果您恢复它 您就不能 debugger now type the follo
  • HTML/VBA Click 事件未触发

    这是我第一次在 StackOverflow 上发布问题 到目前为止 我已经能够通过 VBA 帮助论坛解决我的大部分问题 我的问题很简单 我有一个自动数据拉取 我需要在其中导出数据 我过去曾在这方面取得过成功 但这次略有不同 我尝试单击以生成
  • 动态速度计 javascript 或 jquery 插件

    我希望有动态ajax插件在页面上显示速度计 一个想法是我设置一个背景并旋转针 有人知道相关插件吗 这里有一些供您参考 http bernii github com gauge js http bernii github com gauge
  • 如何使用 JavaScript 中的值填充下拉列表?

    我在 Tridion CMS 扩展中的功能区工具栏按钮中添加了一个按钮 单击该按钮后 将显示一个弹出页面 其中包含两个下拉菜单 通过更改第一个下拉控件中的值 我应该填充第二个下拉控件的值 就我而言 我正在使用ASP drop down li
  • Node js 使用中间件重定向进行过多重定向

    在我的 Node js 应用程序 我使用的是express 4 x 中 我想检查用户是否已登录 如果用户未登录 我想重定向到我的登录页面 然后我在中间件中这样做 服务器 js app use function req res next if
  • 如何使用 jest 模拟第三方库

    我正在开发一个node js应用程序使用nestjs我有一堂课叫LoggerService如下 export class LoggerService private logger Rollbar constructor this logge
  • 即使我可以监视其他方法,也无法监视事件处理程序

    我想使用 Jest Jasmine Enzyme 测试 React 中的事件处理程序 MyComponent js import React from react class MyComponent extends React Compon
  • Node.js - console.log 不显示数组中的项目,而是显示 [Object]

    我在注销对象内数组的内容时遇到问题 实际的物体看起来像这样 var stuff accepted item1 item2 rejected response Foo envelope from The sender to new item1
  • javascript中按tab键时如何调用函数?

    我有一个这样的功能 function whenEmpty field if field value field style backgroundColor ffcccc alert Please fill the field field f
  • 通过 node-http-proxy 保留基于 cookie 的会话

    我有一个简单的基于 Express 的 Node js Web 服务器 用于开发 JavaScript 应用程序 我将服务器设置为使用 node http proxy 来代理应用程序向在不同域和端口上运行的 Jetty 服务器发出的 API
  • 如果链接包含特定文本,jQuery 将类添加到 href

    我的网站上的列表中有一些动态填充的链接 这些链接链接到文件 是否可以使用 jQuery 查看文件名是否以 pdf 结尾 并在 href 或类似的链接文本以 mp3 结尾时添加一个类 例如 我的列表中有以下链接 文件1 pdf 歌曲1 mp3
  • Typeahead.js substringMatcher 函数说明

    我只是在做一些研究Typeahead js这是一个非常酷的图书馆 感谢文档 我已经成功地获得了一个基本的示例 该文档也非常好 但是我试图弄清楚以下代码块实际上在做什么 var substringMatcher function strs r
  • 将数组排序为第一个最小值、第一个最大值、第二个最小值、第二个最大值等

    编写一个JS程序 返回一个数组 其中第一个元素是第一个最小值 第二个元素是第一个最大值 依此类推 该程序包含一个函数 该函数接受一个参数 一个数组 该函数根据要求返回数组 输入示例 array 2 4 7 1 3 8 9 预期输出 1 9
  • Twitter 嵌入时间轴小部件

    我继续下载http platform twitter com widgets js http platform twitter com widgets js And the http platform twitter com embed t
  • JavaScript 代码在不使用 ActiveX 的情况下截取网站屏幕截图

    我有一个用户与之交互的 JavaScript 应用程序 我需要保存当前界面的外观 裁剪出我需要的部分 或者通过指定div只拍摄我需要的部分 然后发送回服务器 显然任何外部服务都无法做到这一点 我需要一个 JavaScript 或Flash
  • 数据表日期范围过滤器

    如何添加日期范围过滤器 like From To 我开始进行常规搜索和分页等工作 但我不知道如何制作日期范围过滤器 我正在使用数据表 1 10 11 版本 My code var oTable function callFilesTable
  • 如何在 gulp.src 中使用基本正则表达式?

    我正在尝试选择两个文件gulp src highcharts js and highcharts src js 当然 我知道我可以使用数组表达式显式添加这两个表达式 但出于学习目的 我尝试为它们编写一个表达式 我读过可以使用简单的正则表达式
  • 在 GWT 中,在任何主机页标记上添加事件处理程序

    我想为任何标签添加 MouseOver 事件处理程序 举个例子 我想为旧版 HTML 页面中的每个锚点页面添加事件处理程序 继GWT指南 http code google com webtoolkit doc 1 6 DevGuideUse

随机推荐

  • Mysql——压缩包方式安装教程

    一 Mysql压缩包下载方式 zip版 5 7及8 0 的下载需到官方网站下载 不同版本对应能安装在不同的操作系统下 本次介绍的是mysql 8 0 30 winx64在win10下的安装方式 下载网址 MySQL Download MyS
  • android模拟器与宿主机通讯

    android模拟器与PC的端口映射 一 概述 Android系统为实现通信将PC电脑IP设置为10 0 2 2 自身设置为127 0 0 1 而PC并没有为Android模拟器系统指定IP 所以PC电脑不能通过IP来直接访问Android
  • Mysql增强半同步模式_MySQL增强半同步的搭建实验,和一些参数的个人理解

    环境信息 role ip port hostname master 192 168 188 101 4306 mysqlvm1 slave 192 168 188 201 4306 mysqlvm1 1 5306 6306 7306 MyS
  • eclipse搜索类快捷键

    习惯的编辑器可以提高编程效率 熟悉的快捷键可以提高工作效率 本文更新eclipse中常用的搜索快捷键 打开资源快捷键 Ctrl Shift R 通过在搜索框中输入名字可以很方便的在项目或工作空间中找某个文件 支持模糊查询功能 例如输入文件的
  • Linux防火墙

    关于linux系统防火墙 centos5 centos6 redhat6系统自带的是iptables防火墙 centos7 redhat7自带firewall防火墙 ubuntu系统使用的是ufw防火墙 必要操作 linux系统防火墙开放相
  • AOP之5种增强方法应用范例

    林炳文Evankaka原创作品 转载请注明出处http blog csdn net evankaka Spring AOP 提供了 5 种类型的通知 它们分别是 Before Advice 前置通知 After Returning Advi
  • PyTorch 手把手搭建神经网络 (MNIST)

    推荐下我自己建的Python学习群 856833272 群里都是学Python的 如果你想学或者正在学习Python 欢迎你加入 大家都是软件开发党 不定期分享干货 还有免费直播课程领取 包括我自己整理的一份2021最新的Python进阶资
  • python写入文件后换行_python写入文件自动换行问题的方法

    现在需要一个写文件方法 将selenium的脚本运行结果写入test result log文件中 首先创建写入方法 def write result str writeresult file r D eclipse4 4 1 script
  • 一些文件头

    由这些文件头即使文件后缀被乱改也可以通过查看二进制文件查出文件的匹配格式 当然这就是一些播放器识别文件的方法 1 从Ultra edit 32中提取出来的 JPEG jpg 文件头 FFD8FF PNG png 文件头 89504E47 G
  • 浅析进程与线程之间的区别

    文章目录 浅析进程与线程之间的区别 从最普遍的答案出发 什么是计算机资源 计算资源 存储资源 I O设备资源 什么是进程 线程 操作系统怎样给进程分配资源的 操作系统怎样调度进 线程的 进程的上下文切换 为什么需要线程 参考链接 浅析进程与
  • mybatis generator

    文章目录 generatorConfig xml GeneratorSqlmap java log4j properties lib maven pom generatorConfig xml
  • 【deep_thoughts】30_PyTorch LSTM和LSTMP的原理及其手写复现

    文章目录 LSTM API 手写 lstm forward 函数 LSTMP 修改 lstm forward 函数 视频链接 30 PyTorch LSTM和LSTMP的原理及其手写复现 哔哩哔哩 bilibili PyTorch LSTM
  • Ubuntu 下安装 OpenSSH Server

    Ubuntu 下安装 OpenSSH Server 是无比轻松的一件事情 需要的命令只有一条 sudo apt get install openssh server 查看返回的结果 如果没有出错 则用putty SecureCRT SSH
  • Deprecated usages detected, please refer to the el-pagination documentation for more details

    遇到这个问题 说明你用el pagination分页器参数传递不正确 在这里插入图片描述 https img blog csdnimg cn 5952bad428654dda8d956181f45183d5 png 我的是由于total没有
  • 在tinymce富文本中插入本地视频解决方案

    前言 最近在改一个别人的项目时候 遇到一个需求 要在tinymce富文本中添加本地视频 tinymce富文本本身是不具备添加本地视频的功能的 需要使用一些其他手段来添加本地视频 小demo截图 方法 1 在富文本的外面写一个添加视频的按钮
  • 第二十九章 Unity关节Joint

    关节组件将刚体连接到另一个刚体或空间中的固定点 关节施加使刚体移动的力 而关节限制功能可以限制该移动 Unity 提供的以下关节可以对刚体组件施加不同的力和限制 从而使这些刚体具有不同的运动 Hinge Joint铰链关节 使两个刚体像被连
  • 软件工程——结构化设计

    一 结构化软件设计的任务 在结构化设计方法中 概要设计阶段将软件需求转化为数据结构和软件的系统结构 概要设计阶段要完成体系结构设计 数据设计及接口设计 详细设计阶段要完成过程设计 二 结构化设计与结构化分析的关系 结构化设计方法的实施要点
  • android 旋转屏幕导致Activity重建解决方法

    横竖屏切换时候activity的生命周期 1 不设置Activity的android configChanges时 切屏会重新调用各个生命周期 切横屏时会执行一次 切竖屏时会执行两次 2 设置Activity的android configC
  • python 根据当前时间创建文件

    在当前目录中批量创建文件 文件名为 Y m d H M S格式的当前时间 精确到秒 为防止出现重名文件 在每创建一个文件后 让线程休眠一秒 import time def create global name localTime time
  • vue-router 源码:前端路由

    前言 在学习 vue router 的代码之前 先来简单了解一下前端路由 前端路由主要有两种实现方法 Hash 路由 History 路由 先来看看这两种方法的实现原理 接着我们将用它们来简单实现一个自己的前端路由 前端路由 Hash 路由