Skip to content

前端路由 history & hash

twobin edited this page Jul 28, 2023 · 1 revision

前端路由 history & hash

创建路由主要分两部分

修改地址栏URL记录

监听URL修改触发事件

实现路由有两种模式hash和history,先来几个概念:

Window.history 是一个只读属性,用来获取History对象的引用,History对象提供了操作浏览器会话历史(浏览器地址栏中访问的页面,以及当前页面中通过框架加载的页面)的接口。

Location 接口表示其链接到的对象的位置(URL)。所做的修改反映在与之相关的对象上。 Document 和 Window 接口都有这样一个链接的Location,分别通过 Document.locationWindow.location 访问。

Window: hashchange event 当URL的片段标识符更改时,将触发hashchange事件 (跟在#符号后面的URL部分,包括#符号)

Window: popstate event 当活动历史记录条目更改时,将触发popstate事件。如果被激活的历史记录条目是通过对history.pushState()的调用创建的,或者受到对history.replaceState()的调用的影响,popstate事件的state属性包含历史条目的状态对象的副本。

  • 会修改浏览器地址栏的方法(仅修改了地址栏显示,不会触发页面刷新):
history.pushState() //H5添加的 用于在浏览历史中添加记录
history.replaceState() //H5添加的 用于在浏览历史中修改记录
location.hash //包含块标识符的DOMString,开头有一个“#”。

这三种方式都能修改浏览器Url地址栏的值,且不会主动触发浏览器reload,不同的是pushState() 和 replaceState() 绝对不会触发 hashchange事件,即使新的URL与旧的URL仅哈希不同也是如此,只有用户点击浏览器倒退按钮和前进按钮,或者使用JavaScript调用back、forward、go方法时才会触发。跨域会报错。但是location.hash 会触发window.hashChange和window.popstate事件。

  • URL修改后的监听事件
hashchange //在浏览器URL中hash发生变化后触发的事件
popstate //H5添加 事件一般与pushState()和replaceState()这两个方法搭配使用, 
当用户点击浏览器的前进后退按钮时, 支持该事件的浏览器就会触发popState事件

popstate事件对象可以获得pushState传递进去的state属性,从而得到变化后的链接地址等

hashchange事件对象中包含变化前后的链接地址(oldURL和newURL)

hashchange只针对同一个文档,如果浏览历史的切换,导致加载不同的文档,该事件也不会触发。

实现思路:

  • hash模式--方法location.hash和hashchange()

hash值变化浏览器不会重新发起请求,但是会触发window.hashChange事件,假如我们在hashChange事件中获取当前的hash值,并根据hash值来修改页面内容,则达到了前端路由的目的。

function hashChange(e){
 // console.log(location.hash)
 // console.log(location.href)
 // console.log(e.newURL)
 // console.log(e.oldURL)
 
 let app = document.getElementById('app')
 
 switch (location.hash) {
   case '#index':
     app.innerHTML = '<h1>这是首页内容</h1>'
   break
   case '#news':
     app.innerHTML = '<h1>这是新闻内容</h1>'
   break
   case '#user':
     app.innerHTML = '<h1>这是个人中心内容</h1>'
   break
   default:
     app.innerHTML = '<h1>404</h1>'
 }
}
 
window.onhashchange = hashChange
 
hashChange() 
  • history模式--方法history.pushState()和popstate()
//改造超链接,阻止默认跳转,默认的跳转是会刷新页面的
document.querySelector('#menu').addEventListener('click',function (e) {
 
 if(e.target.nodeName ==='A'){
 e.preventDefault()
 
 let path = e.target.getAttribute('href')  //获取超链接的href,改为pushState跳转,不刷新页面
 
 window.history.pushState({},'',path)  //修改浏览器中显示的url地址
 render(path)  //根据path,更改页面内容
 
 }
})
 
function render(path) {
 let app = document.getElementById('app')
 switch (path) {
   case '/index':
     app.innerHTML = '<h1>这是首页内容</h1>'
   break
   case '/news':
     app.innerHTML = '<h1>这是新闻内容</h1>'
   break
   case '/user':
     app.innerHTML = '<h1>这是个人中心内容</h1>'
   break
   default:
     app.innerHTML = '<h1>404</h1>'
 }
}
 
//监听浏览器前进后退事件,并根据当前路径渲染页面
 
window.onpopstate = function (e) {
 render(location.pathname)
}
 
//第一次进入页面显示首页
render('/index')