在单页面应用程序中,先后端采用了彻底分离的方法,所以在前端实现路由的切换很是的重要。同时前端实现路由能够减小请求数,缓解后端的压力。在单页面中的路由主要有两种实现方法,一种是经过h5的history api来实现,还有一种是hash来实现。javascript
history的方法主要是应用了几个H5的histroy API:css
在history中建立一个新的访问记录,不能跨域,且不形成页面刷新,stateData为当前页面的一些信息在触发popstate事件的时候能够调用;title为网页的标题;url是浏览器中显示的网址。html
修改当前的访问记录,不能跨域,且不形成页面刷新前端
当回到页面前一页或者后一页的时候触发java
这张图表示了这些api的具体操做。jquery
pushState主要就是向当前页面的后面添加一个新的页面,新的页面地址是第三个参数。 replaceState是把当前页面的地址替换成他的第三个参数,history并不会记录以前的地址 这两个方法都不能进行页面的刷新,因此须要在调用方法的时候执行一下相关路由变化的操做,从而达到页面不切换的效果更改页面的单页面效果。
所以只要在页面跳转的时候改为pushState而后执行当前页面的加载函数,就能够实现不刷新的页面跳转了如: 原来地址是:https://www.baidu.com 而后点击了按钮进行页面跳转就执行函数: history.pushState(data, title, 'https://www.baidu.com/test') 而后浏览器上面的地址已经变成了https://www.baidu.com/test而后同时还有返回的按钮 而后调用一下test页面的渲染方法
这样子会存在一个问题,就是当页面直接打开https://www.baidu.com/test服务器会找不到这个页面而报404的错git
对此错误我想到了两种解决方法github
其二是你跳转页面用不一样参数的形式来跳转页面,如windows
原来地址是:https://www.baidu.com后端
而后点击跳转的时候执行
history.pushState(data, title, '?page=test')
而后浏览器地址栏的地址是https://www.baidu.com?page=test
而后当你访问https://www.baidu.com?page=test页面的时候会打开https://www.baidu.com而后你能够根据page参数的值来判断用户想访问的页面,进行不一样的渲染
<div id="msg"></div> <br><br> <span class="msgBtn" data-route='A'>toFirst</span> <span class="msgBtn" data-route='B'>toSecond</span> <span class="msgBtn" data-route='C'>toThird</span>
样式很简单就是一个显示信息的msg而后三个按钮对应不一样的页面
//路由注册 const message = { undefined: 'massage', A: 'hahahh', B: 'hehehehe', C: 'hohohoho' }; //页面分发加载 function showMsg(el) { const _loc = location.href; let url_msg_id = GetRequest(_loc); el.html(message[url_msg_id.msg]); } //监听前进后退按钮 window.addEventListener('popstate', function (e) { showMsg($('#msg')); }); //点击切换路由 $('.msgBtn').click(function (e) { console.log(e.currentTarget ); history.pushState(null, null, '?msg=' + e.target.dataset.route); showMsg($('#msg')); }); //处理url function GetRequest() { let url = location.search; //获取url中"?"符后的字串 let theRequest = {}; if (url.indexOf("?") !== -1) { let str = url.substr(1); let strs = str.split("&"); for (let i = 0; i < strs.length; i++) { theRequest[strs[i].split("=")[0]] = unescape(strs[i].split("=")[1]); } } return theRequest; } //页面加载渲染 showMsg($('#msg'));
当你点击toFirst会把url的msg参数变成toFirst对应的data-route,而后触发showMsg方法,获取到当前的url的参数在message中找到对应要渲染的字符,渲染在msg上。
效果以下
而后点击toSecond
点击浏览器的返回按钮,经过监听来从新调用showMsg方法,因此会回到这个页面
若是你直接打开http://localhost:63342/history/index.html?msg=C
也会在index.html里面进行showMsg处理来打开对应的页面
<html> <head> <title></title> <style type="text/css"> div { margin: 10px; } .msgBtn { margin: 10px; padding: 10px; border: 1px solid black; } </style> </head> <body> <div id="msg"></div> <br><br> <span class="msgBtn" data-route='A'>toFirst</span> <span class="msgBtn" data-route='B'>toSecond</span> <span class="msgBtn" data-route='C'>toThird</span> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script> <script type="text/javascript"> //路由注册 const message = { undefined: 'massage', A: 'hahahh', B: 'hehehehe', C: 'hohohoho' }; //页面分发加载 function showMsg(el) { const _loc = location.href; let url_msg_id = GetRequest(_loc); el.html(message[url_msg_id.msg]); } //监听前进后退按钮 window.addEventListener('popstate', function (e) { showMsg($('#msg')); }); //点击切换路由 $('.msgBtn').click(function (e) { console.log(e.currentTarget ); history.pushState(null, null, '?msg=' + e.target.dataset.route); showMsg($('#msg')); }); //处理url function GetRequest() { let url = location.search; //获取url中"?"符后的字串 let theRequest = {}; if (url.indexOf("?") !== -1) { let str = url.substr(1); let strs = str.split("&"); for (let i = 0; i < strs.length; i++) { theRequest[strs[i].split("=")[0]] = unescape(strs[i].split("=")[1]); } } return theRequest; } //页面加载渲染 showMsg($('#msg')); </script> </body>
实现思路和以前的大概相同就是变化后面的哈希值,而后经过hashchange监听到哈希值的变化
demo地址 https://github.com/WindStormrage/Single-page-application/blob/master/hash/index.html
这样子是大概实现出了一个单页面的效果可是,还有几个单页面的要素没有体现出来,好比异步静态文件的加载。
而后hash的缺点是,只好设置一层路由若是还有子页面须要路由会比较麻烦,而后还有的是就是#这个字符让url显得很是不美观