首先要学习一下history对象,history对象保存着用户的上网记录,从浏览器窗口打开的那一刻算起。出于安全的考虑,开发人员没法得知用户浏览过的URL。不过,借由用户访问过的页面列表,一样能够在不知道实际URL的状况下实现后退与前进
go(Stirng|number)
使用go方法能够在用户的历史记录中任意跳转,能够向后也能够向前。这个方法接受一个参数,表示向后或向前跳转的页面数的一个整数值。负数表示向后跳转(相似浏览器的后退按钮),正数表示向前跳转(相似浏览器的前进按钮)。来看下例子javascript
//后退一页 history.go(-1) //前进一页 history.go(1) //前进两页 history.go(2)
也能够给go()方法船体一个字符串参数,此时浏览器会跳转到历史记录中包含改字符串的第一个位置,可能后退也可能前进,具体要看哪个位置最近。若是历史记录中不包含该字符串,则什么都不作。例如:html
//跳转到最近的wrox.com页面 history.go("wrox.com") //跳转到最近的douban.cn页面 history.go("douban.cn")
back()
和forward
这两个方法能够来代替go(),模仿浏览器的后退和前进功能前端
back()至关于 go(-1) 后退一个页面html5
forward至关于go(1) 前进一个页面java
注:接下来几个方法是html5新增的方法api
pushState(state,title,url)
该方法的做用是 在历史记录中新增一条记录,改变浏览器地址栏的url,可是,不刷新页面。浏览器
pushState对象接受三个参数,安全
state
:一个与添加的记录相关联的状态对象,主要用于popstate
事件。该事件触发时,该对象会传入回调函数。也就是说,浏览器会将这个对象序列化之后保留在本地,从新载入这个页面的时候,能够拿到这个对象。若是不须要这个对象,此处能够填null
。title
:新页面的标题。可是,如今全部浏览器都忽视这个参数,因此这里能够填空字符串。url
:新的网址,必须与当前页面处在同一个域。浏览器的地址栏将显示这个网址。举个例子,假设当前网址是hello.com/1.html,使用puchState()方法在浏览记录中添加一个新纪录服务器
var stateObj={foo:'bar'} history.pushState(starteObj,'','2.html')
添加新纪录后,浏览器的地址栏马上显示`hello.com/2.html
,但不会跳转到2.html,也不会检查2.html是否存在,它只是成为浏览历史中的最新记录。frontend
总之,pushState()方法不会触发页面刷新,只是致使history对象发生变化,地址栏会有反应,使用该方法后,就可使用history.state属性读出状态对象
var stateObj={foo:'bar'} history.pushState(starteObj,'','2.html') history.state //=> {foo:"bar"}
注意:若是pushState的URL参数设置了一个新的hash值,并不会触发hashchange事件。
replaceState(state,title,url)
replaceState方法的做用是替换当前的历史记录,其余的都与pushState()方法如出一辙。
假定当前网页是example.com/example.html
。
history.pushState({page: 1}, 'title 1', '?page=1') // URL 显示为 http://example.com/example.html?page=1 history.pushState({page: 2}, 'title 2', '?page=2'); // URL 显示为 http://example.com/example.html?page=2 history.replaceState({page: 3}, 'title 3', '?page=3'); // URL 显示为 http://example.com/example.html?page=3 history.back() // URL 显示为 http://example.com/example.html?page=1 history.back() // URL 显示为 http://example.com/example.html history.go(2) // URL 显示为 http://example.com/example.html?page=3
popstate事件是window
对象上的事件,配合pushState()和replaceState()方法使用。当同一个文档
(能够理解为同一个网页,不能跳转,跳转了就不是同一个网页了)的浏览历史出现变化时,就会触发popstate事件。
上面咱们说过,调用pushState()
或者replaceState()
方法都会改变当前的历史记录,仅仅调用pushState()
方法或replaceState()
方法 ,并不会触发该事件,另一个条件是用户必须点击浏览器的倒退按钮或者前进按钮,或者使用js调用history.back()或者history.forward()等方法。
因此,记住popstate事件触发的条件
1. 处在同一个文档(同一个html页面) 2. 文档的浏览历史(即history对象)发生改变
只要符合这两个条件,popstate事件就会触发
具体例子
//index.html <head> <script> window.onpopstate=function(){ alert('location '+document.location+',state '+JSON.stringify(event.state)) } </script> </head> <body> <!--第二步 --> <button onclick="window.history.back()">后退</button> <button onclick="window.history.forward()">前进</button> <!--第一步 --> <button onclick="window.history.pushState(null,'','1.html')">pushState</button> </body>
先点击pushState按钮,在点击后退按钮,就会触发popstate事件
再来一个例子
//index.html <head> <script> window.onpopstate=function(){ alert('location '+document.location+',state '+JSON.stringify(event.state)) } </script> </head> <body> <a href="#one">#one</a> </body>
直接点击a
标签,也能够触发popstate事件
图片来自mdn传送门
前端路由的本质是监听 URL 的变化,而后匹配路由规则,显示相应的页面,而且无须刷新。
目前单页面使用的路由就只有两种实现方式
www.test.com/##/就是Hash URL,当##
后面的哈希值发生变化时,不会向服务器请求数据,能够经过hashchange事件来监听到URL的变化,从而进行跳转页面
网上偷来的一张图:
history模式相比hash模式更美观,须要用到Html5新增的几个api实现,原理以下:
继续偷图:
在介绍实例前先介绍下location对象,location对象提供了与当前窗口中加载的文档有关的信息。它包含如下属性:
属性名 | 例子 | 说明 |
---|---|---|
host | www.hello.com:8080 | 返回服务器名称和端口号(若是有的话) |
hostname | www.hello.com | 返回服务器名称,不带端口号 |
href | http://www.hello.com | 返回当前加载页面的完整url |
pathname | /user/ming | 返回url中的目录 |
hash | #content | 返回url中的hash,若是没有返回空字符串 |
search | ?q=javascript | 返回Url的查询字符串,这个字符串以问号开头 |
咱们在下方的示例中须要用到pathname
属性拿到访问的路径
一个简单的history模式单页面路由实现以下:
//1. 路由规则 const routes={ '/user':user, //user是引入的视图 import user from './view/user' '/about':about } //2. 路由控制类 class Router { start() { // 点击浏览器后退/前进按钮时会触发window.onpopstate事件, 咱们在这时切换到相应页面 // https://developer.mozilla.org/en-US/docs/Web/Events/popstate window.addEventListener('popstate', () => { this.load(location.pathname) }) // 打开页面时加载当前页面 在单页面入口文件中要调用start方法 this.load(location.pathname) } // 前往path, 变动地址栏URL, 并加载相应页面 go(path) { // 变动地址栏URL history.pushState({}, '', path) // 加载页面 this.load(path) } // 加载path路径的页面 load(path) { // 首页 if (path === '/') path = '/foo' // 建立页面实例 const view = new routes[path]() // 调用页面方法, 把页面加载到document.body中 view.mount(document.body) } }
Router类的做用是控制页面根据当前Url切换
start()
go(path)
load(path)