何为前端路由?
路由(Router)这个概念最先是后端出现的,是用来跟后端服务器进行交互的一种方式,通过不同的路径,来请求不同的资源,请求不同的页面是路由的其中一种功能。
前端随着 ajax 的流行,数据请求可以在不刷新浏览器的情况下进行。异步交互体验中最盛行的就是 SPA —— 单页应用。单页应用不仅仅是在页面交互时无刷新的,连页面跳转都是无刷新的,为了实现单页应用,所以就有了前端路由。
前端Router基本功能
一个基本的前端路由至少应该提供以下功能:
-
前端Router可以控制浏览器的 history,使的浏览器不会在 URL 发生改变时刷新整个页面。
-
前端Router需要维护一个 URL 历史栈,通过这个栈可以返回之前页面,进入下一个页面。
前端路由实现原理就是匹配不同的 url 路径,进行解析,然后动态的渲染出区域 html 内容。但是这样存在一个问题,就是 url 每次变化的时候,都会造成页面的刷新。那解决问题的思路便是在改变 url 的情况下,保证页面的不刷新。目前 Router有两种实现方式 History 和 hash。
Hash 路由
URL Hash 的形式类似如下:
1 2 3 4 5 | // 表示文章列表页面 https: //www.limitcode.com/#/list // 表示文章详情页面 https: //www.limitcode.com/#/detail |
# 后面的内容即我们说的 hash 值。hash 用于表示页面的一个位置,当浏览器加载完页面后,会滚动到 hash 所指向的位置,这是 URL hash 最初的目的。
由于 hash 在浏览器中的特性,开发者们发现 hash 非常适合用来实现前端 Router。hash 具有实现前端Router的以下特点,我们一起来看看。
-
hash 只作用在浏览器,不会在请求中发送给服务器。
-
hash 发生变化时,浏览器并不会重新给后端发送请求加载页面。
-
修改 hash 时会在浏览器留下历史记录,可以通过浏览器返回按钮回到上一个页面。
-
hash 发生变化时会触发 hashchange 事件,在该事件中可以通过 window.location.hash 获取到当前 hash值。
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 | // router.js function Router() { this .routes = [] /* 添加路由 */ this .add = function (re, handler) { this .routes.push({re, handler}) } /* 监听 url 变化 */ this .listen = function () { //路由切换 window.addEventListener( 'hashchange' , function (event) { var hash = window.location.hash for ( var i = 0; i ++; i < this .routes.length) { if (hash === this .routes[i].re) { this .routes[i].handler.apply({}) } } }, false ) } /* 前进到一个新的url */ this .push = function (path) { window.location.hash = path || '' } /* 替换成一个新的url */ this .replace = function (path) { path = path || '' var i = window.location.href.indexOf( '#' ) window.location.replace(window.location.href.slice(0, i >= 0 ? i : 0) + "#" + path) } /* 返回到上一个url */ this .back = function () { window.history.back() } } |
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 | // router.html <!DOCTYPE html> < html lang = "en" > < head > < meta charset = "UTF-8" > < title >Title</ title > < script src = "router.js" ></ script > </ head > < body > < div > < button id = "btn" >点击跳转到 list</ button > </ div > < script > var router = new Router(); router.add('/list', function () { }) router.add('/detail', function () { }) router.listen(); var btn = document.getElementById('btn'); btn.addEventListener('click', function (e) { router.push('/list') }) </ script > </ body > </ html > |
History 路由
History 在H5出现之前,可以使用 History.back() 向后跳转,使用 History.forward() 控制向前跳转。
在 H5 中新增了 history.pushState() 和 history.replaceState(),分别可以添加和修改历史记录。
1 2 3 | window.history.pushState({}, "title" , "https://www.limitcode.com/list" ); window.history.replaceState({}, "title" , "https://www.limitcode.com/detail" ); |
和 hash 一样,使用 pushState 和 replaceState 修改 URL 同样有 hash 具备的特点。浏览器历史记录的变更会触发 window 的 onpopstate 事件,可以根据这个事件来监听 URL的变化。
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 | // router2.js function Router() { this .routes = [] /* 添加路由 */ this .add = function (re, handler) { this .routes.push({re, handler}) } /* 监听 url 变化 */ this .listen = function () { //路由切换 window.addEventListener( 'popstate' , function (event) { var pathname = window.location.pathname for ( var i = 0; i ++; i < this .routes.length) { if (pathname === this .routes[i].re) { this .routes[i].handler.apply({}) } } }) } /* 前进到一个新的url */ this .push = function (path) { window.history.pushState({}, '' , path) } /* 替换成一个新的url */ this .replace = function (path) { window.history.replaceState({}, '' , path) } /* 返回到上一个url */ this .back = function () { window.history.back() } } |
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 | // router2.html <!DOCTYPE html> < html lang = "en" > < head > < meta charset = "UTF-8" > < title >Title</ title > < script src = "router2.js" ></ script > </ head > < body > < div > < button id = "btn" >点击跳转到 list</ button > </ div > < script > var router = new Router(); router.add('/list', function () { }) router.add('/detail', function () { }) router.listen(); var btn = document.getElementById('btn'); btn.addEventListener('click', function (e) { router.push('/list') }) </ script > </ body > </ html > |
History 和 Hash 对比
-
hash 使用 # 后面的内容模拟一个完整路径,不太美观。
-
hash 在请求时不会发送给服务器,用户手动刷新页面,后端接受到了也是同一个地址。
-
History 直接修改浏览器 URL,用户手动刷新页面,后端接受到是不同的地址,需要后端做处理跳转到统一的html页面。
本文转载自:https://www.limitcode.com/detail/5e5e603810dcbf0b1852b3c0.html