初探路由模块知识。
- 路由的分类:
- 前端路由(SPA应用中 Hash / History);
- 后端路由(也称为服务器路由);
- 后端路由:
当服务器接收到客户端发送的 HTTP 请求之后,就会根据请求中的 URL 找到相应的映射函数,并且执行映射函数,最后将映射函数的返回值返回给客户端。
静态资源服务器,所有的 URL 映射函数就是对文件的读取操作;
动态服务器,映射函数可能是读取数据库的数据,或者对数据做一些处理,等等。然后将这些数据处理结果或者文件读取结果,在服务器端生成相应的模板返回给客户端,最后客户端展示。 - 前端路由:
其实对于前端路由来说,映射函数就是做一些 DOM 的显隐,展示出不同的页面。 - 前端路由的实现方案:
- Hash
- History
Hash 的实现原理:
URL 地址栏中 # 后面的内容,可以通过location.hash
获取到,进而通过hashchange
事件来监听 # 后面内容的变化;
通过history.length
可以看到路由总数;/**
*
<ul>
<li><a href="#lyout1">路由1</a></li>
<li><a href="#lyout2">路由2</a></li>
<li><a href="#lyout3">路由3</a></li>
</ul>
<div id="content"></div>
*/
class router {
constructor (hash) {
// hashStr 存储路由
this.hashStr = hash
// 初始化 watchHash 事件
this.watchHash()
// 给 watch 绑定监听事件,bind 改变 watchHash 方法中 this 的指向(window 变为 router)
this.watch = this.watchHash.bind(this)
window.addEventListener('hashchange', this.watch)
}
// 监听路由变化方法
watchHash () {
console.log('this: ', this)
let hash = window.location.hash.slice(1)
this.hashStr = hash
if (this.hashStr) {
if (this.hashStr === 'lyout1') {
document.querySelector('#content').innerHTML = '路由1Content'
} else if (this.hashStr === 'lyout2') {
document.querySelector('#content').innerHTML = '路由2Content'
} else {
document.querySelector('#content').innerHTML = '路由3Content'
}
} else {
document.querySelector('#content').innerHTML = '路由还没有开始,点击路由'
}
}
}
new router()
History 的实现原理:
在 H5 之前,只要浏览器地址栏中的 URL 地址改变,都会触发页面刷新,这个过程要消耗时间和资源。若只是两个页面某一小部分不同,进而重载页面,这无疑是一种浪费。出现 history 之后,只需要知道页面的不同部分,在原有页面重载不同部分,然后通过 History API 就可以实现在不刷新页面的情况下,变化 URL。
History API:
/*
state: 需要保存的数据,此数据在触发 popstate 事件时,可以通过 event.state 获取;
title: 标题,一般入参为 null;
url: 设定新的历史记录的 url。新的 url 必须与当前的 url 的 origin 一直,否则会抛错。
*/
window.history.pushState(state, title, url)
window.history.replaceState(state, title, url)
window.history.back()
window.history.forward()
window.history.go(n)
监听:
window.addEventListener('popstate', function(event) {
// ...
}, false)
只是调用 pushState / replaceState 方法并不会触发该事件,只有用户点击浏览器后退,前进按钮时,或者是通过 js 调用 back / forward / go 方法时才会触发。
如何监听 pushState / replaceState 的变化?
/* 创建全局事件 */
let _wr = function (type) {
let orign = history[type]
return function () {
let rv = orign.apply(this, arguments)
let e = new Event(type)
e.arguments = arguments
window.dispatchEvent(e)
return rv
}
}
/* 重写方法 */
history.pushState = _wr('pushState')
history.replace = _wr('replaceState')
/* 实现监听 */
window.addEventListener('pushState', function (e) {
console.log('pushState')
})
window.addEventListener('replaceState', function (e) {
console.log('replaceState')
})
参考:阿里P7:你了解路由吗?