js中的hash和history

248 阅读2分钟

我们访问一个前端页面,如:juejin.cn 你在代码中使用某种模式管理页面的跳转决定什么形式的后缀访问到对应的页面,本文讨论hash模式和history模式

1. hash模式

在代码内改变window.location.hash,

window.location.hash = 'jiahewanggang'

浏览器地址会变成juejin.cn/#/jiahewang… //域名+hash

并且会触发window.onhashchange方法,然后可以根据不同的hash展示不同的路由

function hashChange(e){
    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()

2. history模式

HTML4中,已经支持window.history对象来控制页面历史记录跳转,常用的方法包括:

  • history.forward():在历史记录中前进一步
  • history.back():在历史记录中后退一步
  • history.go(n):在历史记录中跳转n步骤,n=0为刷新本页,n=-1为后退一页。 这样的代码会让页面刷新跳转

HTML5中,window.history对象得到了扩展,新增的API包括:

  • history.pushState(data[,title][,url]):向历史记录中追加一条记录
  • history.replaceState(data[,title][,url]):替换当前页在历史记录中的信息。
  • history.state:是一个属性,可以得到当前页的state信息。
  • window.onpopstate:是一个事件,在点击浏览器后退按钮或js调用forward()back()go()时触发。监听函数中可传入一个event对象,event.state即为通过pushState()replaceState()方法传入的data参数

这样的方法不会让页面跳转,只会操作改变history,并且触发window.onpopstate就可以决定页面展示什么内容了 ,这时候可以做到和hash模式一样的效果,只改变浏览器地址,但是不跳转刷新,你需要监听这个window.onpopstate就可以决定页面展示什么内容了 浏览器地址会变成juejin.cn/jiahewangga… //域名+路径

class Router {
    constructor(){
        this.routers = []
        this.renderCallback = null
    }
    add(route,callback){
        this.routers.push({
            path:route,
            render:callback
        })
    }
    pushState(path,data={}){
        window.history.pushState(data,'',path)
        this.renderHtml(path)
    }
    listen(callback){
        this.renderCallback = callback
        this.changeA()
        window.onpopstate = ()=>this.renderHtml(this.getCurrentPath())
        this.renderHtml(this.getCurrentPath())
    }
    changeA(){
        document.addEventListener('click', (e)=> {
            if(e.target.nodeName==='A'){
                e.preventDefault()
                let path = e.target.getAttribute('href')
                this.pushState(path)
            }
        })
    }
    getCurrentPath(){
        return location.pathname
    }
    renderHtml(path){
        for(let i=0;i<this.routers.length;i++){
            let route = this.routers[i]
            if(path===route.path){
                this.renderCallback(route.render())
                return
            }
        }
    }
}
  
let router = new Router()
router.add('/index',()=>{
    return '<h1>这是首页内容</h1>'
})
router.add('/news',()=>{
    return  '<h1>这是新闻内容</h1>'
})
router.add('/user',()=>{
    return  '<h1>这是个人中心内容</h1>'
})
router.listen((renderHtml)=>{
    let app = document.getElementById('app')
    app.innerHTML = renderHtml
})

3. hash模式和history模式的区别

  • hash 模式会有个/#在地址栏
  • pushState 设置的新 URL 可以是与当前 URL 同源的任意 URL;而 hash 只可修改 # 后面的部分,故只可设置与当前同文档的 URL
  • pushState 设置的新 URL 可以与当前 URL 一模一样,这样也会把记录添加到栈中;而 hash 设置的新值必须与原来不一样才会触发记录添加到栈中
  • pushState 通过 stateObject 可以添加任意类型的数据到记录中;而 hash 只可添加短字符串
  • pushState 可额外设置 title 属性供后续使用
  • hash 兼容IE8以上,history 兼容 IE10 以上
  • history 模式需要后端配合将所有访问都指向 index.html,否则用户刷新页面,会导致 404 错误

懂了吗?请点赞