初探路由模块知识。
- 路由的分类:
- 前端路由(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 = hashif (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 = argumentswindow.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:你了解路由吗?
