现代前端项目多为单页Web应用(SPA),在单页Web应用中路由是其中的重要环节。
SPA 是 single page web application 的简称,译为单页Web应用。
简单的说 SPA 就是一个WEB项目只有一个 HTML 页面,一旦页面加载完成,SPA 不会由于用户的操做而进行页面的从新加载或跳转。 取而代之的是利用 JS 动态的变换 HTML 的内容,从而来模拟多个视图间跳转。css
简单的说,就是在保证只有一个 HTML 页面,且与用户交互时不刷新和跳转页面的同时,为 SPA 中的每一个视图展现形式匹配一个特殊的 url。在刷新、前进、后退和SEO时均经过这个特殊的 url 来实现。
咱们须要实现下满两点:html
hash 模式和 history 模式,就是用来实现上面功能的前端
在url后面加上#,如http://127.0.0.1:5500/前端路由/hash.html#/page1
这个url后面的#/page1
就是hash值html5
基于以上三点咱们能够写一个路由实例web
<!DOCTYPE html> <html lang="en"> <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" /> <title>Document</title> </head> <body> <ul> <li><a href="#/">/</a></li> <li><a href="#/page1">page1</a></li> <li><a href="#/page2">page2</a></li> </ul> <div class="content-div"></div> </body> <script> 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 = window.location.hash.slice(1) || "/"; this.routes[this.currentUrl](); } } RouterClass.init(); const ContentDom = document.querySelector(".content-div"); const changeContent = content => (ContentDom.innerHTML = content); Router.route("/", () => changeContent("默认页面")); Router.route("/page1", () => changeContent("page1页面")); Router.route("/page2", () => changeContent("page2页面")); </script> </html>
History 接口容许操做浏览器的曾经在标签页或者框架里访问的会话历史记录。能够参考下两篇文章对history的说明
https://css-tricks.com/using-the-html5-history-api/
https://developer.mozilla.org/zh-CN/docs/Web/API/History
下面介绍在这个模式下须要用到的apiajax
history.go(n)
:路由跳转几步,n为2往前跳转2个页面,-2日后跳转两个页面history.back()
:路由后退,至关于 history.go(-1)
,用户可点击浏览器左上角的后退按钮模拟此方法history.forward()
:路由前进,至关于 history.go(1)
,用户可点击浏览器左上角的前进按钮模拟此方法history.pushState()
:添加一条路由历史记录,若是设置跨域网址则报错segmentfault
history.pushState
用于在浏览历史中添加历史记录,可是并不触发跳转,此方法接受三个参数,依次为:
state
:一个与指定网址相关的状态对象,popstate
事件触发时,该对象会传入回调函数。若是不须要这个对象,此处能够填null
。
title
:新页面的标题,可是全部浏览器目前都忽略这个值,所以这里能够填null
。
url
:新的网址,必须与当前页面处在同一个域。浏览器的地址栏将显示这个网址。
当活动历史记录条目更改时,将触发popstate事件。若是被激活的历史记录条目是经过对history.pushState()的调用建立的,或者受到对history.replaceState()的调用的影响,popstate事件的state属性包含历史条目的状态对象的副本。
须要注意的是调用history.pushState()或history.replaceState()不会触发popstate事件。只有在作出浏览器动做时,才会触发该事件,如用户点击浏览器的回退按钮(或者在Javascript代码中调用history.back())后端
<!DOCTYPE html> <html lang="en"> <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" /> <title>Document</title> </head> <body> <ul> <li><a href="/">/</a></li> <li><a href="/page1">page1</a></li> <li><a href="/page2">page2</a></li> </ul> <div class="content-div"></div> </body> <script> class RouterClass { constructor(path) { this.routes = {}; // 记录路径标识符对应的cb history.replaceState({ path }, null, path); // 进入状态 this.routes[path] && this.routes[path](); window.addEventListener("popstate", e => {// 当用户点击浏览器的前进或者后退触发 console.log(e.state) 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); console.log(history); this.routes[path] && this.routes[path](); } } RouterClass.init(); const ul = document.querySelector("ul"); const ContentDom = document.querySelector(".content-div"); const changeContent = content => (ContentDom.innerHTML = content); Router.route("/", () => changeContent("默认页面")); Router.route("/page1", () => changeContent("page1页面")); Router.route("/page2", () => changeContent("page2页面")); ul.addEventListener("click", e => { console.log(e.target.tagName); if (e.target.tagName === "A") { e.preventDefault(); Router.go(e.target.getAttribute("href")); } }); </script> </html>
Hash 模式是使用 URL 的 Hash 来模拟一个完整的 URL,所以当 URL 改变的时候页面并不会重载。History 模式则会直接改变 URL,因此在路由跳转的时候会丢失一些地址信息,在刷新或直接访问路由地址的时候会匹配不到静态资源。所以须要在服务器上配置一些信息,让服务器增长一个覆盖全部状况的候选资源,好比跳转 index.html 什么的api
优势跨域
ie8
)hash
的路由实现ajax
请求之外,不会发起其余请求缺点
hash
部份内容,致使后台没法取得url
中的数据,典型的例子就是微信公众号的oauth
验证优势
url
中的参数。后端能够拿到这部分数据browser
的路由实现history.state
来获取当前url
对应的状态信息缺点
hash
路由(只兼容到IE10
)html
文档实例来源:http://www.javashuo.com/article/p-ybhejxib-r.html
官方文档:https://developer.mozilla.org/en-US/docs/Web/API/History_API
优缺点比较:https://juejin.im/post/5b5ec5...