前端路由

前端路由

1.路由是什么

1.1 路由的概念

路由就是“分发请求”,是将互联网的网络信息从源地址传输到目的地址活动。路由通常根据路由表来引导分组传送。将它做成硬件的话,就称作路由器。

前端中的路由就是由URL到界面的映射。

1.2 默认路由和 404 路由

  1. 默认路由:是对IP数据包中的目的地址找不到存在的其他路由时,路由器所选择的路由。即,URL 的 hash 为空时默认选择的 hash值。

  2. 404 路由 / 保底路由:是对IP数据包中的目的地址找不到存在的映射对象时,路由器所选择的路由。即,URL的 hash 在路由表中找不到时(错误时),选择预设的 404 hash。

2.前端路由的三种实现

前两种模式利用了 window.location 接口,将路由存入URL。这个接口表示 window 对象所展示的页面的地址等信息,对于一个完整的 url,location 的 protocol,hostpathnamesearchhash 分别表示了每一部分字段。


例如,对于http://www.google.com.hk/news?s=a#page1,
location.protocol = “http:”
location.host = “www.google.com.hk"(包括hostname和port(80))
location.pathname = “/news”
location.search = “?s=a”
location.hash = “#page1”


2.1 hash 模式

hash 模式通过构建路由表,建立URL到界面之间的映射。然后通过监听 hashchange 来响应URL变化,进而切换界面。

具体地,当用户点击 a 标签时,href 发生变化进而URL变化,随即触发 hashchange 事件。

index.html

1
2
3
4
5
6
7
8
9
10
11
12
<body>
<a href="#1">go to 1</a>
<a href="#2">go to 2</a>
<a href="#3">go to 3</a>
<a href="#4">go to 4</a>

<div id="app"></div>

<div id="div404" style="display: none;">你访问的内容不存在</div>

<script src="main.js"></script>
</body>

main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
const app = document.querySelector("#app");
const div1 = document.createElement("div");
div1.innerHTML = '1';
const div2 = document.createElement("div");
div2.innerHTML = '2';
const div3 = document.createElement("div");
div3.innerHTML = '3';
const div4 = document.createElement("div");
div4.innerHTML = '4';

const routeTable = {
"1": div1,
"2": div2,
"3": div3,
"4": div4
};

function route(container) {
let number = window.location.hash.substr(1);

// 获取当前页面的 id
number = number || 1;

// 获取由 url 映射的 div界面
let div = routeTable[number.toString()];

if (!div) {
div = document.querySelector("#div404");
}

// 渲染 div
div.style.display = "block";

container.innerHTML = "";

// 展示 div
container.appendChild(div);
}

// 初始路由
route(app);

window.addEventListener("hashchange", () => {
route(app);
})

hash 模式的优缺点

优点:兼容性好。任何情况下都可以使用前端路由,例如本地模式下适合使用hash模式做路由。

缺点:SEO不友好。服务器并不能接收 hash 。URL中的 hash 只是在客户端的一种状态标记,当客户端向服务器发送请求时,hash 部分不会被发送。

2.2 history 模式

当服务器将所有前端路由都渲染在同一个页面下时,才可以使用history模式。

history 模式先取消 a 标签的所有默认操作,然后使用 windo.history.pushState() 方法重新设置URL的 location.pathname; 最后封装 onStateChange() 方法通知浏览器重新路由。

index.html

1
2
3
4
5
6
7
8
9
10
11
12
<body>
<a href="/1" class="link">go to 1</a>
<a href="/2" class="link">go to 2</a>
<a href="/3" class="link">go to 3</a>
<a href="/4" class="link">go to 4</a>

<div id="app"></div>

<div id="div404" style="display: none;">你访问的内容不存在</div>

<script src="main.js"></script>
</body>

main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
const app = document.querySelector("#app");
const div1 = document.createElement("div");
div1.innerHTML = "1";
const div2 = document.createElement("div");
div2.innerHTML = "2";
const div3 = document.createElement("div");
div3.innerHTML = "3";
const div4 = document.createElement("div");
div4.innerHTML = "4";
const routeTable = {
"/1": div1,
"/2": div2,
"/3": div3,
"/4": div4
};

function route(container) {
let number = window.location.pathname;

if (number === "/") {
number = "/1";
}

// 获取界面
let div = routeTable[number.toString()];
if (!div) {
div = document.querySelector("#div404");
}
div.style.display = "block";

// 展示界面
container.innerHTML = "";
container.appendChild(div);
}

const allA = document.querySelectorAll("a.link");

for (let a of allA) {
a.addEventListener("click", e => {
e.preventDefault();
const href = a.getAttribute("href");
window.history.pushState(null, `page ${href}`, href);
// 通知
onStateChange();
});
}

route(app);

function onStateChange() {
route(app);
}

history 模式的优缺点

优点:URL 美观,可设置与当前URL同源的任意 URL

缺点:IE8 一下不支持,兼容性没有 hash 模式好,对服务器端的设置有要求。单机版路由不适合使用这种模式。

2.3 memory模式

memory 模式不使用URL存储(不使用 window.location API) ,而是使用本地数据库存储。前端路由一般使用 localStorage 进行存储。

index.html

1
2
3
4
5
6
7
8
9
10
11
12
<body>
<a href="/1" class="link">go to 1</a>
<a href="/2" class="link">go to 2</a>
<a href="/3" class="link">go to 3</a>
<a href="/4" class="link">go to 4</a>

<div id="app"></div>

<div id="div404" style="display: none;">你访问的内容不存在</div>

<script src="main.js"></script>
</body>

main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
const app = document.querySelector("#app");
const div1 = document.createElement("div");
div1.innerHTML = "1";
const div2 = document.createElement("div");
div2.innerHTML = "2";
const div3 = document.createElement("div");
div3.innerHTML = "3";
const div4 = document.createElement("div");
div4.innerHTML = "4";
const routeTable = {
"/1": div1,
"/2": div2,
"/3": div3,
"/4": div4
};

function route(container) {
let number = window.localStorage.getItem("pagePath");

if (!number) number = "/1";

let div = routeTable[number.toString()];

if (!div) div = document.querySelector("#div404");


div.style.display = "block";
container.innerHTML = "";
container.appendChild(div);
}

const allA = document.querySelectorAll("a.link");

for (let a of allA) {
a.addEventListener("click", e => {
e.preventDefault();
const href = a.getAttribute("href");
window.localStorage.setItem("pagePath", href);
route(app);
})
}

route(app);

memory 模式的优缺点

memory 模式应用场景:适合于没有使用路径的本地app。例如react native、weex

缺点:由于 memory 模式没有使用URL,因此本质上就是一个单机版路由,路由不可分享。


版权声明:本文作者为「Andy8421」.本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!