_单页面路由">
赞
踩
一个demo本地可直接使用,另外我也部署在了http://wangkehan.com/hash可以直接查看
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>router</title> <style> html, body { width: 100%; height: 100%; margin: 0; } div.router-wrap { width: 100%; height: 100%; background: #fefefe; } a { padding: 10px; color: pink; font-size: 25px; font-weight: bold; text-decoration: none; } </style> </head> <body> <div class="router-wrap"> <a href="#/black">黑色</a><br> <a href="#/green">绿色</a><br> <a href="#/red">红色</a> </div> <script> // 创建Router构造函数 // currentHash为当前hash值,routes为路径对象 function Router() { this.currentHash = '/'; this.routes = {}; } // 注册路径,每个路径对应一个回调函数。 Router.prototype.route = function (path, callback) { this.routes[path] = callback } // 更新页面函数 Router.prototype.refresh = function () { // #/green => /green this.currentHash = location.hash.slice(1) || '/'; // 调用对应路径注册的更新函数 this.routes[this.currentHash](); } // 初始化 Router.prototype.init = function () { var self = this; window.addEventListener('load', function () { self.refresh(); }, false); window.addEventListener('hashchange', function () { self.refresh(); }); } </script> <script> var wrap = document.querySelector('.router-wrap'); window.Router = new Router(); Router.route('/', function () { wrap.style.backgroundColor = '#fefefe'; }); Router.route('/black', function () { wrap.style.backgroundColor = 'black'; }); Router.route('/green', function () { wrap.style.backgroundColor = 'green'; }); Router.route('/red', function () { wrap.style.backgroundColor = 'red'; }); Router.init(); </script> </body> </html>
首先创建一个Router构造函数,初始化当前的url和一个routes对象。
定义了三个方法:
route方法 — 该方法用于在实例化router对象之后,注册路由,对于不同的路由,执行不同的回调函数 。
refresh方法 — 在路由切换时,执行该方法刷新页面。
init方法 — 在注册完路由之后,执行该方法,该方法主要注册了两个事件,主要是添加hashchange监听事件。
html5中的history api包括两个方法history.pushState()和history.replaceState(),包含一个事件history.onpopstate。
1、history.pushState(stateObj, title, url) —向历史栈中写入数据
2、history.replaceState(stateObj, title, url)
参数和pushState一样
区别:替换修改浏览历史中当前纪录
3、popstate事件
定义:每当同一个文档的浏览历史(即history对象)出现变化时,就会触发popstate事件。
只调用pushState方法或replaceState方法 ,并不会触发该事件,只有用户点击浏览器倒退按钮和前进按钮,或者调用back、forward、go方法时才会触发。
使用:为popstate事件指定回调函数。这个回调函数的参数是一个event事件对象,它的state属性指向pushState和replaceState方法为当前URL所提供的状态对象(stateObj)
demo:
如果在本地测试:因为pushState的url和当前的Url必须是同源的,而file://的形式是不存在同源的说法的,所以我们必须用http://localhost的方式。
因此,为了方便查看,我将history的实现效果部署在了http://wangkehan.com/history可以直接查看
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>router</title> <style> html, body { width: 100%; height: 100%; margin: 0; } div.router-wrap { width: 100%; height: 100%; background: #efefef; } a { display: inline-block; padding: 10px; color: pink; font-size: 25px; font-weight: bold; text-decoration: none; } </style> </head> <body> <div class="router-wrap"> <a href="/black" class="history-link">黑色</a><br> <a href="/green" class="history-link">绿色</a><br> <a href="/red" class="history-link">红色</a> </div> <script> // 创建Router构造函数 function Router() { this.currentRoute = ''; this.routes = {}; this.init(); } // 注册路由函数 Router.prototype.route = function (path, callback) { // 根据type类型,选择相应的history api。 this.routes[path] = function (type) { if (type == 1) { history.pushState({path: path}, '', path); } else if (type == 2) { history.replaceState({path: path}, '', path); } callback(); } } // 更新页面 Router.prototype.refresh = function (path, type) { this.routes[path](type); } // 初始化 Router.prototype.init = function () { var self = this; // 重新加载函数 window.addEventListener('load', function () { self.currentRoute = location.href.slice(location.href.indexOf('/', 8)); console.log(self.currentRoute); self.refresh(self.currentRoute); }); // 当用户点击前进后退按钮时触发函数 window.addEventListener('popstate', function () { console.log('history.state.path:', history.state.path); self.currentRoute = history.state.path; self.refresh(self.currentRoute, 2); }, false); // 对所有的link标签进行绑定事件 var historyLinks = document.querySelectorAll('.history-link'); for (var i = 0, len = historyLinks.length; i < len; i++) { historyLinks[i].onclick = function(e) { // 阻止默认 e.preventDefault(); self.currentRoute = e.target.getAttribute('href'); self.refresh(self.currentRoute, 1); } } } </script> <script> var wrap = document.querySelector('.router-wrap'); // 实例化Router window.Router = new Router(); // 注册路由,实现相应功能 Router.route('/', function () { wrap.style.backgroundColor = '#efefef' }); Router.route('/black', function () { wrap.style.backgroundColor = 'black'; }); Router.route('/green', function () { wrap.style.backgroundColor = 'green'; }); Router.route('/red', function () { wrap.style.backgroundColor = 'red'; }); </script> </body> </html>
pushState设置的新URL可以是与当前URL同源的任意URL;而hash只可修改#后面的部分,故只可设置与当前同文档的URL
pushState设置的新URL可以与当前URL一模一样,这样也会把记录添加到栈中;而hash设置的新值必须与原来不一样才会触发记录添加到栈中
pushState通过stateObject可以添加任意类型的数据到记录中;而hash只可添加短字符串
pushState可额外设置title属性供后续使用
hash模式仅改变hash部分的内容,而hash部分是不会包含在HTTP请求中的:
http://oursite.com/#/user/id // 如重新请求只会发送http://oursite.com/
故在hash模式下遇到根据URL请求页面的情况不会有问题。
而history模式则会将URL修改得就和正常请求后端的URL一样
http://oursite.com/user/id
在此情况下重新向后端发送请求,如后端没有配置对应/user/id的路由处理,则会返回404错误。
解决方法:
如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面
1、一般场景下,hash 和 history 都可以,如果更在意颜值,# 符号不在URL中展示可以选择history模式
2、history —— 利用了 HTML5 中新增的api,无法在低版本浏览器中使用
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。