前端路由应该理解的一些前置知识

news2024/12/23 15:16:50

1. URI和URL

URI相比,我们更熟悉URLURL正是使用web浏览器等访问web页面时需要输入的网页地址。比如我们经常输入的 https://www.baidu.com/ 就是 URL

1.1 统一资源标识符

URIUniform Resource Identifier 的缩写。RFC2396分别对这三个单词进行了以下定义:

  • Uniform

规定统一的格式可以方便处理多种不同类型的资源,而不用根据上下文环境来识别资源指定的访问方式。

  • Resopurce

可标识的任何资源。不仅是文档文件,图像或者服务等能够区别于其他类型的,全部可作为资源,它可以是多个对象的集合体。

  • Identifier

标识可标识的对象,也可以称为标识符。

综上所述,URI就是由某个协议方案表示的资源的定位标识符。洗衣方案是指访问资源时所使用的协议类型名称。HTTP就是协议的一种方案,除此之外,还有ftpfileTELNET30多种标准URI协议方案。

协议方案由互联网号码分配局管理颁布。URI用字符标识某一互联网资源,而URL表示资源的地点,可见URL是URI的子集

1.1.1 URI的通用语法

URI的通用语法由 5 个组件组成:

URI = scheme:[//authority]path[?query][#fragment] 

其中,authority 组件可以由以下3个组件组成:

authority = [userinfo@]host[:post] 
  • authority 中,userinfo作为登陆欣欣,通常形式为指定用户名和密码,当从服务器端获取资源时作为身份人中凭证使用,userinfo为可选项。
  • 服务器地址 host 在使用绝对路径URI时需指定访问的服务器地址,地址可用为被 DNS 解析的域名,或者是 IPv4 地址以及 IPv6 地址。
  • post 为服务器连接的网络端口号,作为可选项,如果不指定,则自动使用默认的端口号。
  • path 为带层次的文件路径,指定服务器上的文件路径,以访问特定的资源。
  • query 为查询字符串,针对指定路径的文件资源,可使用查询字符串传入任意查询参数。

统一资源标识符 URI 通用语法中列举了几种 URI 例子,如下所示:

ftp://ftp.is.co.za//rfc/rfc1808.txt
http://www.itef.org/rfc/rfc2396.txt
ldap://[2001.db8::7]/c=GB?objectClass?one
mailto:John.Doe@example.com
news:comp.infosystems.www.servers.unix
tel:+1-826-555-1212
telnet://192.0.2.16a:18/
urn:oasis:names:specification:docbook:dxt:xml:4.1.2 

1.1.2 URL的通用语法

统一资源定位器URL作为URI的一种,如同网络的门牌,表示了一个互联网资源的 地址,如 https://www.baidu.con 表示通过 HTTP 协议从主机名为 www.baidu.com 的主机上获取首页资源。

URL的语法定义与URI一致:

URL = scheme:[//authority]path[?query][#fragment] 

https://www.baidu.com:80/foo/baz?title=moment 为例,其中 https 表示加密的超文本传输协议,www.baidu.com 为服务器的地址,80 为服务器上的都安口号,foo/baz 为资源路径,?title=moment为路径的查询,以 "?" 开头,各个参数是以 "&" 为分割,以等号 "=" 分开参数名称与数据。

1.2.1 URI和URL总结

URL是一种具体的URI,它是URI的一个子集,它不仅唯一标识资源,而且还提供了定位该资源的信息。URI是一种语义上的抽象概念,可以是绝对的,也可以是相对的,而URL则必须提供足够的信息来定位,是绝对的。

总的来说,人的身份证号就是URI,通过身份证号可以让我们能找到具体的一个人。而通过具体的地址去查找某个人,例如广东省广州市天河区某某大学一栋101宿舍的云梦泽,通过具体的地址也可以找到某个人,也起到了URI的作用,所以URLURI的子集。URL是描述某一资源的具体位置。

2. 浏览器记录

浏览器记录是浏览器中各个页面用户的导航记录。在现代浏览器中,浏览器记录并没有直接的 API 可获取,其可通过 window.history.length 获取当前记录栈的长度信息。浏览器记由浏览器统一管理,并不属某个具体的页面,与页面形式及其内存均无关系。

window.history 对象上存在着诸多属性,通过 lib.dom.d.ts 文件中查看History有以下定义:

interface History {readonly length: number;scrollRestoration:"auto" | "manual";readonly state: any;back(): void;forward(): void;go(delta?: number): void;pushState(data: any, unused: string, url?: string | URL | null): void;replaceState(data: any, unused: string, url?: string | URL | null): void;
} 

2.1.1 history.pushState

在 HTML 文档中,history.pushState() 方法向当前浏览器会话的历史堆栈中添加一个状态(state)。

history.pushState 方法作为 HTML5 特性的一部分,目前被广泛使用。history.pushState 用于无刷w新增历史栈记录,调用 history.pushState 方法可改变浏览器路径。

pushState() 需要三个参数: 一个状态对象, 一个标题 (目前被忽略), 和一个可选的URL.详情可看 MDN文档。其基本语法如下所示:

pushState(state:Object, title:string,[url:string]):undefined 

当设置第三个参数URL时,可改变浏览器URL,且不会刷新浏览器。

history.pushState(null, null, "/foo/bar");
console.log(location.pathname); // /foo/bar 

如果URL中包含 Unicode 字符,则浏览器也会将字符按 UTF-8 编码。

history.pushState(null, null, "/中文");
console.log(location.pathname); // /%E4%B8%AD%E6%96%87 

通过以下代码示例通过设置state,titleurl创建一条新的历史记录:

// index.html文件
 <body><script> const state = { nickname: "moment", age: 7 };const title = "";const url = "title.html";history.pushState(state, title, url); </script></body>// title.html文件<body><h1>这个是title页面</h1><div class="age"></div><div class="nickname"></div><script> const nickname = document.querySelector(".nickname");const age = document.querySelector(".age");nickname.innerHTML = window.history.state.nickname;age.innerHTML = window.history.state.age; </script></body> 

上例代码通过 pushState 改变浏览器URL,并传进了 state 参数,页面跳转到 title.html 的页面,在 title.html 文件中通过 history.state 获取传进来的数据并通过 innerHTNL 展示出来,结果如下所示:

因为历史栈由浏览器统一管理,不属于某个具体页面,并不存在于页面的内存中,所以历史栈在刷新页面后不会丢失,栈中记录的各 state 对象也为持久化存储,在导航过程中也不会丢失。

histiry.pushState 使用结构化拷贝算法进行序列化存储,会将拷贝后的结果记录在历史栈记录中。结构化拷贝算法除了能拷贝基本类型,还能考悲剧更多的对象类型。相比 JSON 的序列化,这样的序列化更为安全,如循环引用的对象,结构化序列的手段将会序列化成功,而 JSON 的序列化将会报错,原因在于结构化蓄力的手段保存了每一个访问过的对象的记录,遇到复制过的对象会进行跳过。

结构化拷贝算法要注意特殊的场景,如果 history.pushStatestate 对象中有 dom节点、error对象、function函数等,调用 history.pushState方法会抛出异常,且对某些对象的特定属性,如 regExplastIndexObject对象的 settergetter 等,结构化拷贝的过程都会丢失。

2.1.2 历史栈变化

history.pushState 的调用会引起历史栈的变化,浏览器通常会维护一个用户访问过的历史栈,以便用户进行导航。用户通常可以通过浏览器的前进后退按钮或者调用 window.history.go 等方法在历史栈中进行移动,可理解为下图所示的栈指针,不改变历史栈的内容,栈内的记录数量不会发生改变:

当调用 history.pushState 方法时,历史栈的内容会被修改,行为表现为添加历史栈的栈记录,如上图所示,urlstate会被推到栈顶。历史栈会有一个指针指向栈的其中一个内容,栈指针所指向的内容正是浏览器当前所运行的url所对应的页面。

当调用 history.pushState({a:3},null,'/c') 方法后,则栈记录加1,栈指针也会指向最新的栈记录位置。通过 history.length 能查看当前历史栈的长度。

浏览器提供了两个 API 接口用以调用浏览器本身自带的返回向前,它们分别是 back() 方法和 forward() 方法。其中 back() 方法会在会话历史记录中向后移动一页。如果没有上一页,则此方法调用不执行任何操作。而在会话历史中向前移动一页。它与使用delta参数为 1 时调用 history.go(delta)的效果相同。 还有一个 go 方法从会话历史记录中加载特定页面,你可以使用它在历史记录中前后移动,具体取决于 delta 参数的值,具体语法如下:

window.history.go(delta); 

delta 参数可选,相当于当前页面你要去往历史页面的位置。负值表示向后移动,正值表示向前移动。因此,例如:history.go(2) 向前移动两页,history.go(-2) 则向后移动两页。如果未向该函数传参或delta相等于0,则该函数与调用 location,reload() 具有相同的效果。具体有以下示例:

// 向后移动一页 back()
window.history.go(-1);

// 向前移动一页 forward()
window.history.go(1);

// 向后移动两页
window.history.go(-2);

// 向前移动两页
window.history.go(2); 

2.1.3 history.replaceState

history.replaceState 的用法与 history.pushState 非常相似,区别在于 history.replaceState 将修改当前的历史记录想而不是新建一个,其语法为:

history.replaceState(stateObj, title[, url]); 

history.replaceState 不会改变历史栈中记录的数量,它只会更新当前栈的信息,历史栈的长度不会发生变化。

2.1.4 通过相对路径太黏和修改浏览器记录

history.replaceStatehistory.pushState,除支持绝对路径导航外,还支持相对路径导航:如:

window.history.pushState(null, null, "../one");
window.history.replaceState(null, null, "./one.two"); 

它们的规则和在 Node,js 中的 url.resolve(),具体可参考 Node.js官方文档 ,两者相对路径的解决规则一致。对于相对路径导航,其遵循以下规则:

  • 如果路径以 "/" 开头,则会替换掉整个路径;
  • 如果路径不以 "/" 开头,则会得到相对当前URI地址的路径(在浏览器无base元素的存在的情况下),跟你混路径解决规则会替换 URL 地址中的最后一级目录,即最后一个 "/" 分隔符后缪按的路径部分,如:
// 当前路径为 /one/two/three
console.log(location.pathname); // /one/two/three
window.history.pushState(null, null, "four");
console.log(location.pathname); // /one/two/four 

如果当前路径的最后一个字符为 "/",则可以认为 "/" 后紧接空字符串,执行相对路径导航会替换空字符串部分。

如果路径中含有 "." "..",则表示当前路径及上一级路径。

// 当前路径为 /one/two/three
console.log(location.pathname); // /one/two/three
window.history.pushState(null, null, "./four");
console.log(location.pathname); // /one/two/four
// 当前级路径改为 five 下一级路径改为 six
window.history.pushState(null, null, "./five/././six");
console.log(location.pathname); // /one/two/five/six 

对于 ".." 操作符,其表明回到上一句路径。

// 当前路径为 /one/two/three
console.log(location.pathname); // /one/two/three
window.history.pushState(null, null, "../four");
console.log(location.pathname); // /one/four

// 当前路径为 /one
console.log(location.pathname); // /one
window.history.pushState(null, null, "../five/six");
console.log(location.pathname); // /five/six 

3. Location

Location 接口表示其链接到的对象的位置(URL)。所做的修改反映在与之相关的对象上。 DocumentWindow 接口都有这样一个链接的 Location,分别通过 Document.locationWindow.location 访问。其中 Document.locationWindow.location指向同一个对象:

console.log(window.location === document.location); // true 

通过 lib.dom.d.ts 文件查看 Location 的类型定义,主要有以下属性和方法:

interface Location {hash: string;host: string;hostname: string;href: string;toString(): string;readonly origin: string;pathname: string;port: string;protocol: string;search: string;assign(url: string | URL): void;reload(): void;replace(url: string | URL): void;
} 

3.1.1 hash

Location 接口的 hash 属性返回一个 USVString,其中会包含 URL 标识中的 '#' 和后面 URL 片段标识符。这里 fragment 不会经过百分比编码(URL 编码)。如果 URL 中没有 fragment,该属性会包含一个空字符串,“”。

<a id="myAnchor" href="/moment.com#elegance">Examples</a>
<script> const link = document.querySelector("a");console.log(link.hash);
</script 

如果设置的 location.hash 值与浏览器的 URL 地址的 hash值相同,就不会触发任何事件,也不会添加任何历史记录。或者如果前后两次对 location.hash 设置了相同的值,则第一次 locationn.hash 设置生效,第二次相同的设置不会产生任何事件和历史记录。

3.1.2 host

Location 接口的 host 属性是包含了主机的一段 USVString,其中包含:主机名,如果 URL 的端口号是非空的,还会跟上一个 ':' ,最后是 URL 的端口号。

console.log(location.host);
// 该输出结果在 create-react-app创建的项目中输出的是 localhost:3000
// 在 live Server 打开的文件打开的html文件输出的 127.0.0.1:5500
// 而在普通方式打开的html文件中输出的空字符串 

hostname 属性则不携带端口号。

3.1.3 href

Location 接口的 href 属性是一个字符串化转换器 (stringifier), 返回一个包含了完整 URLUSVString 值,且允许 href 的更新。

<a id="myAnchor" href="/moment.com#elegance">Examples</a>
<script> const link = document.querySelector("a");console.log(link.href); // http://127.0.0.1:5500/moment.com#elegance </script> 

3.1.4 replace

history.replaceState 类似,window.location.replace会替换当前的栈记录,但在设置绝对路径中,这意味着用户将不能用 "后退" 按钮再次回到旧页面。

location.href = "https://www.foo.com";
location.href = "https://www.bar.com";
location.replace("https://www.baz.com"); 

在上面的例子中,由于在 www.bar.com 中调用了 location.href 方法,www.bar.com 的页面记录将替换为 https://www.baz.com 的页面记录。当用户在 https://www.baz.com 页面单机浏览器 "后退" 按钮是,将回到 www.foo.com 页面。

4. 浏览器相关事件

4.1.1 popstate事件

每当激活同一文档中不同的历史记录条目时,popstate 事件就会在对应的 window 对象上触发。如果当前处于激活状态的历史记录条目是由 history.pushState() 方法创建的或者是由 history.replaceState() 方法修改的,则 popstate 事件的 state 属性包含了这个历史记录条目的 state 对象的一个拷贝。

调用 history.replaceState()history.pushState() 不会触发 popstate 事件。当移动栈指针或单机浏览器的 "前进""后退" 按钮时,将触发 popstate 事件,可通过 window.addEventListener 监听该事件。

举个例子🌰,有以下的历史栈,当前历史栈指针正指向 two.html 页面:

我们通过以下代码来监听 popstate 事件的变化:

window.addEventListener("popstate", function (event) {console.log(event);
}); 

我们通过点击 two.html 页面的前进按钮,前往 three.html 的页面,控制台会有以下输出:

而回退到 one.html 页面又有以下输出,也正是我们所预料到的:

history.state 同步的是记录栈中的值,每次导航都会获得新的 state 对象。栈记录中的 state 对象是深拷贝存储在浏览器中的,无论在浏览器进行导航,还是刷新当前页面或是关闭浏览器页签再恢复,历史栈的内容都存在且不会被销毁。

当前后两次设置相同的 location.hash 值时,不会触发两次 popstate 事件。若通过 location.href 设置 hash 值,则无论前后设置的值是否相同,都会触发 popstate 事件。当前后两次设置的值相同时,只添加一个历史栈。

4.2.1 hashchange 事件

hashchange 事件用于监听浏览器值的 hash值变化,其监听方式为:

window.addEventListener("hashchange", function (event) {console.log(event);
}); 

通过下列代码来演示一下在 hashchange 事件的事件相应函数中,可以获取独享 HashChangeEvent,具体有以下属性和方法:

通过上面的动图可以看出,hashchange 事件可以通过设置 location.hash、在地址栏手动修改 hash、调用 window.history.go、在浏览器中单击 "前进""后退" 按钮等方式触发。且每次事件都会得到当前的 url 和旧的 url

值得注意的是,pushState 不会触发 hashChange 事件,即使前后当行的 URLhash 部分发生改变,也是如此。

最后

最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/113822.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring的基础用法

前言 上面的目录内容本文章不一定都会写到&#xff0c;本次的文章将非常简略&#xff0c;主写主要内容&#xff0c;次要内容需要读者有一定的学习基础才可以看懂以及掌握&#xff0c;本文章比较偏向于理论复习&#xff0c;注意是理论&#xff0c;本文章代码不多&#xff0c;代…

【python】异常处理及程序调试(一)

异常类和异常处理 一、程序的错误类型 语法错误&#xff1a;不符合语法规则而产生的错误&#xff0c;如&#xff1a;标识符命名错误&#xff0c;缩进错误&#xff0c;访问未定义的变量等。这类错误在编辑或解释时就会被检测出来&#xff0c;产生这类错误&#xff0c;程序将会…

node.js+uni计算机毕设项目基于微信小程序点餐与结账系统LW(程序+小程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等…

2023跨年代码(烟花+自定义文字+背景音乐+雪花+倒计时)

2023年快要到来啦&#xff0c;很高兴这次我们又能一起度过~ 目录 一、前言 二、跨年烟花 三、效果展示 倒计时 2023​编辑 兔圆圆​编辑 四、编码实现 index.html 烟花&#xff0c;雪花&#xff0c;背景音乐&#xff0c;页面样式 index.js 自定义文字 五、获取代码 需…

算法 | 如何通过Math.random()方法实现X平方或更多次方的概率?

前言 本文主要介绍Java中Math.random()方法以及该方法的简单应用。 每种语言都有随机方法&#xff0c;在Java中的随机方法有Math.random()方法、Random类。 Math.random Math.random()方法的返回值的是double类型&#xff0c;其返回值的范围为[0,1)&#xff0c;包含0&#…

每日笔记

下周要做一个hmi获取登录码、小程序码的新接口&#xff0c;需要用到新的知识来实现这个功能 接口英文名 getUnlimitedQRCode 功能描述 该接口用于获取小程序码&#xff0c;适用于需要的码数量极多的业务场景。通过该接口生成的小程序码&#xff0c;永久有效&#xff0c;数量…

Es客户端学习

版本&#xff1a;opensearch-rest-high-level-client-2.3.0.jar&#xff0c;httpcore-nio-4.4.11.jar&#xff0c;httpasyncclient-4.1.4.jar 问题背景 初始化es索引逻辑是监听大数据团队消息&#xff0c;然后异步写入es(org.opensearch.client.RestHighLevelClient#bulkAsyn…

七、Kubernetes1.25应用部署、发布的两种方式

1、概述 通过现代的 Web 服务&#xff0c;用户希望应用程序能够 24/7 全天候使用&#xff0c;开发人员希望每天可以多次发布部署新版本的应用程序。 容器化可以帮助软件包达成这些目标&#xff0c;使应用程序能够以简单快速的方式发布和更新&#xff0c;而无需停机。这段话是Ku…

智子商城项目实践开发文档

ZutShop Junior practical training project 在csdn暂存一下开发文档 本人大三做的实训项目&#xff0c;前后端分离。 后端&#xff1a;https://github.com/roydonGuo/ZutShop 前端使用Vue&#xff0c;前端项目地址&#xff1a;https://github.com/roydonGuo/ZutShop-Vue 0. …

python利用json和pyecharts画折线图实例

目录 一.json模块对数据进行处理 二.利用pyecharts画折线图 三.利用pyecharts画美、日、印三国家折线图 四.本文数据集 注&#xff1a;本次实验的数据在文章最后面&#xff0c;我已上传至百度网盘 一.json模块对数据进行处理 上面三个txt文本是这三个国家疫情爆发相关的数据 …

linux有磁盘空间却显示不足 linux中inode使用率过高处理办法

linux中inode使用率过高处理办法 前几天收到监控告警&#xff0c;说Inode节点空间不足&#xff0c;之前没处理过这种问题&#xff0c;所以记录一下处理过程&#xff0c;便于以后查阅。 Inode使用率高并不会影响系统正常运行和新文件的创建&#xff0c;但是当使用率达到100%的…

【Linux】Linux编译器gcc/g++的使用

今天不学习&#xff0c;明天变垃圾。 文章目录一、程序的翻译过程1.预处理&#xff08;1.2.3把你的代码编译成二进制代码&#xff09;2.编译&#xff08;C语言 > 汇编语言&#xff09;3.汇编&#xff08;无法被执行的二进制文件&#xff0c;为什么捏&#xff1f;&#xff09…

腾讯云Windows 轻量应用服务器如何搭建 FTP 服务?

本文档介绍如何在 Windows 操作系统的轻量应用服务器上通过 IIS 搭建 FTP 站点。 本文搭建 FTP 服务组成版本如下&#xff1a; Windows 操作系统&#xff0c;本文以系统镜像 Windows Server 2012 为例。IIS&#xff1a;Web 服务器&#xff0c;本文以 IIS 8.5 为例。 步骤1&am…

自行车在线租赁管理系统的设计与实现

自行车在线租赁管理系统 摘 要 随着Internet的不断发展&#xff0c;在线租赁在现实生活中的使用和普及&#xff0c;自行车在线租赁行业成为近年内出现的一个新行业&#xff0c;并且能够成为大众广为认可和接受的行为和选择。设计自行车在线租赁管理系统的目的就是借助计算机…

(四)汇编语言——简单程序

目录 编写程序的工作过程 编写汇编源程序 伪指令 汇编指令 注释 编写步骤 编译连接 编译 连接 运行 总结 编写程序的工作过程 接下来&#xff0c;我们简单介绍一下一个汇编程序&#xff0c;从写出到最后执行&#xff0c;他到底经历了哪些步骤。 编写汇编源程序 首先…

vue3 antd项目实战——修改table表格的默认样式(一)调整table表格每行(row)行高过高问题

vue3 antd项目实战——修改ant design vue table组件的默认样式&#xff08;调整每行行高&#xff09;知识调用场景复现实际操作解决a-table表格padding过宽知识调用 文章中可能会用到的知识链接vue3ant design vuets实战【ant-design-vue组件库引入】css样式穿透&#xff08;…

node.js+uni计算机毕设项目基于微信小程序的房屋交易平台(程序+小程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等…

智能超表面(RIS)辅助双功能雷达和通信波束形成设计(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 智能超表面&#xff0c;也叫做“可重配智能表面”&#xff0c;或者“智能反射表面”&#xff0c;英文为RIS&#xff08;Reconf…

springboot消息

发送短信的简单原理 activemq 5.17 版本的 需要java11 环境 mq 网页版本控制台 账号密码为admin 指定发送的名 即上图的默认名为itheima 监听器 自动监听消息 接受 如果接受到消息 还想再其他地方使用 可以使用sendto 使用管理员权限 登录 然后列出插件 安装插件 r…

Java 注解 自定义注解 注解的解析

目录 一、认识Java自带注解 二、自定义注解 1、认识元注解 2、自定义注解 3、注解的使用 4、反射解析注解 一、认识Java自带注解 jdk中自带了一些注解&#xff0c;如下四个&#xff1a; Override类方法的的重写注解Deprecated类或方法被废除的注解FunctionalInterface函…