Bootstrap

前端路由之——hash

(。・∀・)ノ゙嗨

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

刚看完上面那段话,可能有人会有疑问:URL中的#是什么,如何用hash实现前端路由呢?

别着急,往下看 φ(゜▽゜*)♪~~~

首先我们来说一下URL中的井号(其实也叫 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);

了解了hash的基本概念后,我们再来解决下一个问题,如何用它实现前端路由

~~( ̄▽ ̄)~*

首先我们需要使用一个可以根据监听哈希变化触发的事件 —— hashchange 事件。

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

下面是一个用hash实现前端路由的栗子:

<!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>


实现的效果图:
在这里插入图片描述
我们可以观察到点击不同的跳转按钮,对应url后面的hash也在改变。

这就是一个简单的前端路由~~

该兴趣的同学可以尝试一下 ヾ( ̄▽ ̄)ByeBye

;