前端路由

在谈前端路由之前,我们先了解一下:

从输入URL到页面加载完成是一个怎样的过程

1. 输入地址

当我们开始在浏览器中 输入网址的时候,浏览器其实已经开始在智能的匹配可能得到的URL了,他会从历史记录、书签等地方,找到已经输入的字符串可能对应的URL,然后给出智能的提示。
 
  对于Google chrome这种聪明的浏览器,他甚至会直接从缓存中把网页展示出来,也就是说在你还没有戳下enter键的时候,页面就已经展示在你面前了,详细情况先不解释。

2. 浏览器查找域名的IP地址

  • 导航的第一步是找出访问域的IP地址,DNS查找过程如下:
    浏览器缓存:浏览器缓存DNS记录一段时间,然而操作系统并没有告诉浏览器每个DNS记录的生存时间,因此浏览器会将其缓存一段固定的时间(一般在2到30分钟之间)

  • 操作系统缓存:如果浏览器缓存不包含所需的记录,则浏览器进行系统调用(Windows中的gethostbyname)。操作系统有自己的缓存。

  • 路由器缓存:请求继续到您的路由器,路由器通常具有自己的DNS缓存。

  • ISP DNS缓存:检查的下一个是ISP的DNS缓存,这里自然也会有一个缓存。

  • 递归搜索:ISP的DNS服务器开始递归搜索,从根名称服务器通过.com顶级名称服务器到Facebook的名称服务器。通常来讲,DNS服务器将在缓存中具有.com名称服务器的名称,因此对根名称的服务器的命中是不必要的。

3. 浏览器向web服务器发送一个http请求

一般网页的动态主页不会存在于缓存中,因为动态页面都会有一个非常短暂的时间设为过期时间,因此 浏览器会将此请求发往服务器,get请求命名要提取自己的URL(例如:http://baidu.com), 浏览器识别自己的请求头,并说明自己接受哪一类类型的响应

4. 服务器的永久重定向响应

(从http://baidu.com 到 http://www.baidu.com

服务器收到请求后开始响应,将http://baidu.com重定向到 http://www.baidu.com

为什么服务器一定要 重定向而不是直接发会用户想看的网页内容呢?

这个问题有好多有意思的答案。
其中一个原因跟搜索引擎排名有关。你看,如果一个页面有两个地址,就像htp://wwwigoro.com/和tp:/igoro.com/,搜索弓擎会认为它们是两个网站,结果造成每一个的搜索链接都减少从而降低排名。而搜索引擎知道301永久重定向是什么意思,这样就会把访问带www的和不带www的地址归到同一个网站排名下。

还有一个是用不同的地址会造成缓存友好性变差。当一个页面有好几个名字时,它可能会在缓存里出现好几次。

5. 浏览器跟踪重定向地址

浏览器知道http://www.baidu.com是正确的URL,因此它会发出另一个获取信息

6. 服务器处理请求

服务器将受到get请求,处理它并发送回应

7. 服务器返回一个http响应

服务器生成并发回响应,包含响应头,响应正文,缓存时间信息,以及其他信息

8. 浏览器显示HTML

9. 浏览器发送请求获取嵌入在HTML中的资源(如:图片、音频、视频、CSS、JS等)

10. 浏览器发送异步请求(如ajax请求)

11. 页面构建完成

【在浏览器的地址上输入一个网址时,究竟发生了什么?】


前端路由有两种模式:hash模式和history模式,再谈这这种模式之前,我们先来了解一下什么是hash~~~

URL中的hash(井号)

1.#的含义

#代表网页中的一个位置,其右边的字符,就是该位置的标识符。比如

http://www.example.com/index.html#print

就是代表index.html中的print位置。浏览器会自动把print位置滚动到页面可视区域内。

设置方法:

step1:设置一个锚点<a href="#print">定位到print位置

step2:在页面需要定位的内容加上id="print"。例如:<div id="print"></div>

测试:step1设置的锚点,step2中id为print的内容会滚动到页面顶端(可观察滚动条的距离)。同时,++页面的url末端中会出现#print的哈希值。++

2.HTTP请求不包含#

#号是用来指导浏览器动作的,对服务器端完全无用。所以,HTTP请求中不包含#。

比如,访问下面的网址:

http://jquery.com#hello

浏览器实际发出的请求时这样的:

可以看到,只是请求了http://jquery.com,没有请求"#hello"的部分。

3.#后面的字符

在第一个#后面出现的任何字符,都 会被浏览器解读为位置标识符。这意味着,这些字符都不会被发送到服务器端

比如,下面的URL的原意是指定一个颜色值:

http://jquery.com/?color=#fff

但是浏览器实际发出的请求是:

可以看到,"#fff"被省略了。只有将#转码为%23,浏览器才会将其作为实义字符处理。也就是说,上面的网址应该被写成:

 http://jquery.com/?color=%23fff

4.改变#不触发网页重载

单单改变#后的内容,浏览器只会滚动到相应位置,不会重新加载网页。

浏览器不会重新向服务器请求页面。

5.改变#会改变浏览器的访问历史

每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用"后退"按钮,就可以回到上一个位置。

这对于ajax应用程序特别有用,可以用不同的#值,表示不同的访问状态,然后向用户给出可以访问某个状态的链接。

(值得注意的是,上述规则对IE 6和IE 7不成立,它们不会因为#的改变而增加历史记录。)

6.window.location.hash 读取#值

window.location.hash 这个属性可读可写。读取时,可以用来判断网页状态是否改变;写入时,则会在不重载网页的前提下,创造一条访问历史记录。

7.onhashchange事件

这是一个HTML 5新增的事件,当#值发生变化时,就会触发这个事件。IE8+、Firefox 3.6+、Chrome 5+、Safari 4.0+支持该事件。

它的使用方法有三种:

1.window.onhashchange = func;

2.<body onhashchange="func();">

3.window.addEventListener("hashchange", func, false);

早期的路由都是后端实现的,直接根据 url 来 reload 页面,页面变得越来越复杂服务器端压力变大,随着 ajax 的出现,页面实现非 reload 就能刷新数据,也给前端路由的出现奠定了基础。我们可以通过记录 url 来记录 ajax 的变化,从而实现前端路由。

下来主要讲两种主流方式实现前端路由。

hash

我们经常在 url 中看到 #,这个 # 有两种情况,一个是我们所谓的锚点,比如典型的回到顶部按钮原理、Github 上各个标题之间的跳转等,路由里的 # 不叫锚点,我们称之为 hash,大型框架的路由系统大多都是哈希实现的。

同样我们需要一个根据监听哈希变化触发的事件 —— hashchange 事件

我们用 window.location 处理哈希的改变时不会重新渲染页面,而是当作新页面加到历史记录中,这样我们跳转页面就可以在 hashchange 事件中注册 ajax 从而改变页面内容。

<!DOCTYPE html>
<html lang="zh">
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<meta http-equiv="X-UA-Compatible" content="ie=edge">
		<style>
			li {
				display: inline-block;
				margin: 0 30px 30px 0;
			}
		</style>
		<title></title>
	</head>
	<body>
		<ul>
			<li><a href="#/" class="">turn white</a></li>
			<li><a href="#/orange" class="">turn orange</a></li>
			<li><a href="#/purple=123" class="">turn purple</a></li>
		</ul>
	</body>
	<script>
		function Router() {   //这是一个对象 {/: ƒ, /orange: ƒ, /purple=123: ƒ}
			this.routes = {};
			this.currentUrl = '';
		}
		
		//在Router.prototype原型上设置方法,第一个设置路由,第二个路由跳转,第三个页面初始化
		Router.prototype.route = function(path, callback) {
			this.routes[path] = callback || function() {};
			console.log(this.routes)
		};
		Router.prototype.refresh = function() {
			//console.log(location) //Location 对象Location 对象包含有关当前 URL 的信息。Location 对象是 Window 对象的一个部分,可通过 window.location 属性来访问。
			//console.log(location.hash);   #/purple=123
			this.currentUrl = location.hash.slice(1) || '/';  //截取#后面的内容
			this.routes[this.currentUrl](); //根据属性名 执行对应的函数
		};
		Router.prototype.init = function() {
			window.addEventListener('load', this.refresh.bind(this), false); //加载首页
			window.addEventListener('hashchange', this.refresh.bind(this), false);  //当URL的片段标识符更改时,将触发hashchange事件
		}
		
		//自定义封装一个路由
		window.Router = new Router();
		window.Router.init();
		var content = document.querySelector('body');
		// change Page anything
		function changeBgColor(color) {
			content.style.backgroundColor = color;
		}
		Router.route('/', function() {
			changeBgColor('white');
		});
		Router.route('/orange', function() {
			changeBgColor('orange');
		});
		Router.route('/purple=123', function() {
			changeBgColor('purple');
		});
	</script>
</html>


History API

【js中的 history 对象】

【javascript history对象详解 *】

一、简单介绍 history 中的操作

1.window.history.back(),后退

2.window.history.forward(),前进

3.window.history.go(num),前进或后退指定数量历史记录

4.window.history.pushState(state, title, utl),在页面中创建一个 history 实体。直接添加到历史记录中。

参数:state:存储一个对象,可以添加相关信息,可以使用 history.state 读取其中的内容。

title:历史记录的标题

url:创建的历史记录的链接。进行历史记录操作时会跳转到该链接。

5.window.history.replaceState(),修改当前的 history 实体。

参数:state:存储一个对象,可以添加相关信息,可以使用 history.state 读取其中的内容。
title:历史记录的标题(目前浏览器不支持)。
url:创建的历史记录的链接。进行历史记录操作时会跳转到该链接。

6.popstate 事件,history 实体改变时触发的事件。

7.window.history.state,会获得 history 实体中的 state 对象。

重点说其中的两个新增的API history.pushStatehistory.replaceState

pushStatereplaceState是一个HTML5的新接口,他们的作用非常大,可以做到改变网址却不需要刷新页面

pushState方法

接受三个参数,依次为:

state:一个与指定网址相关的状态对象,popstate事件触发时,该对象会传入回调函数。如果不需要这个对象,此处可以填null。

title:新页面的标题,但是所有浏览器目前都忽略这个值,因此这里可以填null。

url:新的网址,必须与当前页面处在同一个域。浏览器的地址栏将显示这个网址。

最常用的方法:window.history.pushState(null,null,'download?id=1');

完整使用:var oState= {title: '下载' };window.history.pushState(oState, '下载', 'download?id=1');

replaceState方法

和pushState原理一样使用也一样:

最常用的方法:window.history.replaceState(null,null,'download?id=1');

完整使用:var oState= {title: '下载' };window.history.replaceState(oState, '下载', 'download?id=1');

特点:replaceState不会加入到历史记录里面,用history.go(-1)会跳过当前页面相当于是history.go(-2)。

<!DOCTYPE HTML>
<!-- this starts off as http://example.com/line?x=5 -->
<title>Line Game - 5</title>
<p>You are at coordinate <span id="coord">5</span> on the line.</p>
<p>
	<a href="?x=6" onclick="go(1); return false;">Advance to 6</a> or
	<a href="?x=4" onclick="go(-1); return false;">retreat to 4</a>?
</p>
<script>
	var currentPage = 5; // prefilled by server!!!!
	function go(d) {
		setupPage(currentPage + d);
		history.pushState(currentPage, document.title, '?x=' + currentPage);
	}
	onpopstate = function(event) {
		setupPage(event.state);
	}

	function setupPage(page) {
		currentPage = page;
		document.title = 'Line Game - ' + currentPage;
		document.getElementById('coord').textContent = currentPage;
		document.links[0].href = '?x=' + (currentPage + 1);
		document.links[0].textContent = 'Advance to ' + (currentPage + 1);
		document.links[1].href = '?x=' + (currentPage - 1);
		document.links[1].textContent = 'retreat to ' + (currentPage - 1);
	}
</script>

如果还想有更多了解,可以参考一下文章:

【两种模式】

【方法及适用场景】

【前端路由的两种模式:hash模式和history模式】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值