前端路由跳转基本原理(代码片段)

xiaonian8 xiaonian8     2022-12-13     768

关键词:

目前前端三杰 Angular、react、vue 都推介单页面应用 SPA 开发模式,在路由切换时替换 DOM Tree 中最小修改的部分 DOM,来减少原先因为多页应用的页面跳转带来的巨量性能损耗。它们都有自己的典型路由解决方案,@angular/router、react-router、vue-router。

一般来说,这些路由插件总是提供两种不同方式的路由方式:Hash 和 History,有时也会提供非浏览器环境下的路由方式 Abstract,在 vue-router 中是使用了外观模式将几种不同的路由方式提供了一个一致的高层接口,让我们可以更解耦的在不同路由方式中切换。

值得一提的是,Hash 和 History 除了外观上的不同之外,还一个区别是:Hash 方式的状态保存需要另行传递,而 html5 History 原生提供了自定义状态传递的能力,我们可以直接利用其来传递信息。

下面我们具体看看这两种方式都有哪些特点,并提供简单的实现,更复杂的功能比如懒加载、动态路径匹配、嵌套路由、路由别名等等,可以关注一下后面的 vue-router 源码解读方面的博客。

 

1. Hash

1.1 相关 Api

Hash 方法是在路由中带有一个 #,主要原理是通过监听 # 后的 URL 路径标识符的更改而触发的浏览器 hashchange 事件,然后通过获取 location.hash 得到当前的路径标识符,再进行一些路由跳转的操作,参见 MDN

  1. location.href:返回完整的 URL

  2. location.hash:返回 URL 的锚部分

  3. location.pathname:返回 URL 路径名

  4. hashchange 事件:当 location.hash 发生改变时,将触发这个事件

比如访问一个路径 http://sherlocked93.club/base/#/page1,那么上面几个值分别为:

# http://sherlocked93.club/base/#/page1

  "href": "http://sherlocked93.club/base/#/page1",
  "pathname": "/base/",
  "hash": "#/page1"

复制代码注意:Hash 方法是利用了相当于页面锚点的功能,所以与原来的通过锚点定位来进行页面滚动定位的方式冲突,导致定位到错误的路由路径,因此需要采用别的办法,之前在写 progress-catalog 这个插件碰到了这个情况。

 

1.2 实例

这里简单做一个实现,原理是把目标路由和对应的回调记录下来,点击跳转触发 hashchange 的时候获取当前路径并执行对应回调

class RouterClass 
  constructor() 
    this.routes =         // 记录路径标识符对应的cb
    this.currentUrl = ‘‘    // 记录hash只为方便执行cb
    window.addEventListener(‘load‘, () => this.render())
    window.addEventListener(‘hashchange‘, () => this.render())
  
  
  /* 初始化 */
  static init() 
    window.Router = new RouterClass()
  
  
  /* 注册路由和回调 */
  route(path, cb) 
    this.routes[path] = cb || function() 
  
  
  /* 记录当前hash,执行cb */
  render() 
    this.currentUrl = location.hash.slice(1) || ‘/‘
    this.routes[this.currentUrl]()
  

具体实现参照 CodePen(https://codepen.io/SHERlocked93/pen/GzZWYw)

如果希望使用脚本来控制 Hash 路由的后退,可以将经历的路由记录下来,路由后退跳转的实现是对 location.hash 进行赋值。但是这样会引发重新引发 hashchange 事件,第二次进入 render 。所以我们需要增加一个标志位,来标明进入 render 方法是因为回退进入的还是用户跳转

class RouterClass 
  constructor() 
    this.isBack = false
    this.routes =         // 记录路径标识符对应的cb
    this.currentUrl = ‘‘    // 记录hash只为方便执行cb
    this.historyStack = []  // hash栈
    window.addEventListener(‘load‘, () => this.render())
    window.addEventListener(‘hashchange‘, () => this.render())
  
  
  /* 初始化 */
  static init() 
    window.Router = new RouterClass()
  
  
  /* 记录path对应cb */
  route(path, cb) 
    this.routes[path] = cb || function() 
  
  
  /* 入栈当前hash,执行cb */
  render() 
    if (this.isBack)       // 如果是由backoff进入,则置false之后return
      this.isBack = false   // 其他操作在backoff方法中已经做了
      return
    
    this.currentUrl = location.hash.slice(1) || ‘/‘
    this.historyStack.push(this.currentUrl)
    this.routes[this.currentUrl]()
  
  
  /* 路由后退 */
  back() 
    this.isBack = true
    this.historyStack.pop()                   // 移除当前hash,回退到上一个
    const  length  = this.historyStack
    if (!length) return
    let prev = this.historyStack[length - 1]  // 拿到要回退到的目标hash
    location.hash = `#$ prev `
    this.currentUrl = prev
    this.routes[prev]()                       // 执行对应cb
  

实现参考 CodePen(https://codepen.io/SHERlocked93/pen/GzZWYw)

广州品牌设计公司https://www.houdianzi.com PPT模板下载大全https://redbox.wode007.com

2. html5 History Api

2.1 相关 Api

HTML5 提供了一些路由操作的 Api,关于使用可以参看  这篇 MDN 上的文章,这里就列举一下常用 Api 和他们的作用,具体参数什么的就不介绍了,MDN 上都有

  1. history.go(n):路由跳转,比如n为 2 是往前移动2个页面,n为 -2 是向后移动2个页面,n为0是刷新页面

  2. history.back():路由后退,相当于 history.go(-1)

  3. history.forward():路由前进,相当于 history.go(1)

  4. history.pushState():添加一条路由历史记录,如果设置跨域网址则报错

  5. history.replaceState():替换当前页在路由历史记录的信息

  6. popstate 事件:当活动的历史记录发生变化,就会触发 popstate 事件,在点击浏览器的前进后退按钮或者调用上面前三个方法的时候也会触发,参见 MDN

2.2 实例

将之前的例子改造一下,在需要路由跳转的地方使用 history.pushState 来入栈并记录 cb,前进后退的时候监听 popstate 事件拿到之前传给 pushState 的参数并执行对应 cb,因为借用了浏览器自己的 Api,因此代码看起来整洁不少

class RouterClass 
  constructor(path) 
    this.routes =         // 记录路径标识符对应的cb
    history.replaceState( path , null, path)  // 进入状态
    this.routes[path] && this.routes[path]()
    window.addEventListener(‘popstate‘, e => 
      const path = e.state && e.state.path
      this.routes[path] && this.routes[path]()
    )
  
  
  /* 初始化 */
  static init() 
    window.Router = new RouterClass(location.pathname)
  
  
  /* 注册路由和回调 */
  route(path, cb) 
    this.routes[path] = cb || function() 
  
  
  /* 跳转路由,并触发路由对应回调 */
  go(path) 
    history.pushState( path , null, path)
    this.routes[path] && this.routes[path]()
  

Hash 模式是使用 URL 的 Hash 来模拟一个完整的 URL,因此当 URL 改变的时候页面并不会重载。History 模式则会直接改变 URL,所以在路由跳转的时候会丢失一些地址信息,在刷新或直接访问路由地址的时候会匹配不到静态资源。因此需要在服务器上配置一些信息,让服务器增加一个覆盖所有情况的候选资源,比如跳转 index.html 什么的,一般来说是你的 app 依赖的页面,事实上 vue-router 等库也是这么推介的,还提供了常见的服务器配置。

前端路由原理(代码片段)

...端路由:早期传统MVC网站路由都是服务端主导,前端通过不同URL请求后端,后端框架有专门的路由模块用来匹配URL地址,然后根据不同地址和参数调用相关处理程序并返回html页面给前端。前端路由:后来前后... 查看详情

前端hash路由基本原理,及代码的基本实现

...,随着ajax的出现,页面实现非reload就能刷新数据,也给前端路由的出现奠定了基础。我们可以通过记录url来记录ajax的变化,从而实现前端路由。(可以根据不同的url来展示不同的页面,很好的优化了页面的交互体验。)目前有... 查看详情

06-前端开发框架vue技术应用总结(代码片段)

文章目录VUE基础MVVM设计VUE绑定原理设计虚拟DOM树分析VUE编程步骤实践绑定与指令应用绑定样式分析(了解):计算属性应用实践生命周期函数应用Axios方式的Ajax请求Get请求Post请求VUE组件化开发组件设计基本步骤运行分析组件类型组... 查看详情

前端路由原理及vue-router介绍(代码片段)

前端路由原理本质就是监听URL的变化,然后匹配路由规则,显示相应的页面,并且无须刷新。目前单页面使用的路由就只有两种实现方式hashhistorywww.test.com/##/ 就是HashURL,当 ## 后面的哈希值发生变化时,不会向服务器... 查看详情

前端路由hashhistory原理(代码片段)

本文参考https://www.cnblogs.com/tugenhua0707/p/10859214.html先来看下后端路由的实现方式:1.浏览器向服务器发出请求。2.服务器监听到80端口,如果有请求过来,那么就解析url地址。3.服务器根据客户端的路由配置,然后就返回相应的信息(... 查看详情

flutter之基本路由,命名路由跳转,返回上一页,替换路由和返回根路由——flutter基础系列(代码片段)

...xff1a;今天为大家介绍一下Flutter是如何进行页面跳转,路由管理的。一、基本路由1、基本路由使用假设我们需要从A页面跳转到basic页面,则我们需要在A页面引入import'../basic.dart';然后在A页面通过以下方法跳转:Ra... 查看详情

hcna——ip路由原理静态路由基本配置(代码片段)

HCNA——IP路由原理、静态路由基本配置在互联网中进行路由选择所使用的设备,或者说,实现路由的设备,我们称之为路由器。路由器关键功能检查数据包的目的地确定信息源发现可能的路由选择最佳路由验证和维护路由信息什... 查看详情

浅谈前端路由原理hash和history(代码片段)

浅谈前端路由原理hash和history🎹序言🎸一、前端路由原理1、SPA2、什么时候需要路由🎷二、Hash模式1、定义2、网页url组成部分(1)了解几个url的属性(2)演示3、hash的特点🎺三、History模式1、定义... 查看详情

前端路由的实现(代码片段)

HTML5HistoryHistoryinterface是浏览器历史记录栈提供的接口,通过back(),forward(),go()等方法,我们可以读取浏览器历史记录栈的信息,进行各种跳转操作。从HTML5开始,Historyinterface提供了两个新的方法:pushState(),replaceState()使得我们可以... 查看详情

flutter学习-路由(代码片段)

flutter-路由1.路由管理1.1认识Flutter的路由1.2Route1.3Navigator2.路由的基本使用2.1基本跳转2.1.1错误一2.1.2跳转、返回、相互传值2.2命名路由的使用2.2.1基础跳转2.1.2传值2.1.3路由的钩子(onGenerateRoute)2.1.4onUnknownRoute我们通常用屏... 查看详情

11flutter--路由和导航(代码片段)

路由导航在本章中不仅仅会谈到页面的渲染,还会阐述数据是如何进行传递的。页面跳转基本使用页面跳转发送数据页面跳转返回数据页面跳转基本使用在Flutter中页面的跳转称之为路由,它们由导航器Navigator组件管理。导航器... 查看详情

vrrp协议与keepalived基本原理实例演示(代码片段)

VRRP是什么?VRRP(VirtualRouterRedundancyProtocol,虚拟路由器冗余协议)是一种容错协议,保证当主机的下一条路由器出现故障时,由另一台路由器来代替出现故障的路由器进行工作,从而保持网络通信的连续性和可靠性。VRRP相关术... 查看详情

前端路由简介以及vue-router实现原理(代码片段)

后端路由简介路由这个概念最先是后端出现的。在以前用模板引擎开发页面时,经常会看到这样http://www.xxx.com/login大致流程可以看成这样:浏览器发出请求服务器监听到80端口(或443)有请求过来,并解析url路径根据服务器的路... 查看详情

前端路由简介以及vue-router实现原理(代码片段)

后端路由简介路由这个概念最先是后端出现的。在以前用模板引擎开发页面时,经常会看到这样http://www.xxx.com/login大致流程可以看成这样:浏览器发出请求服务器监听到80端口(或443)有请求过来,并解析url路径根据服务器的路... 查看详情

vuerouter实现原理(代码片段)

...:hash|history|abstract一、实现方式:hash模式早期的前端路由跳转就是利用location.hash来实现的,像下面的链接 查看详情

vuerouter实现原理(代码片段)

...:hash|history|abstract一、实现方式:hash模式早期的前端路由跳转就是利用location.hash来实现的,像下面的链接 查看详情

微前端实现原理研究总结(代码片段)

微前端实现原理研究总结前言微前端实现方案子应用生命周期改写子应用子应用打包主应用中注册子应用主应用和子应用的路由模式主应用路由拦截主应用获取子应用并执行生命周期函数主应用加载并解析子应用获取html文件内... 查看详情

微前端实现原理研究总结(代码片段)

微前端实现原理研究总结前言微前端实现方案子应用生命周期改写子应用子应用打包主应用中注册子应用主应用和子应用的路由模式主应用路由拦截主应用获取子应用并执行生命周期函数主应用加载并解析子应用获取html文件内... 查看详情