为什么要路由?
从前的页面都是多个HTML文件,通过a
标签进行跳转。
现代化的框架为了提高可维护性,提出组件化、模块化。
页面的渲染模式变为了 “JS渲染页面”。
页面无法通过url
跳转了,因为HTML文件只存在一个,就是首页,其它HTML页面都是不存在的。
就需要一个 路由程序,来控制浏览器地址切换,并展示对应页面组件。
路由原理
从上面,我们可以推出,路由的要求
- 改变路由(但是不刷新页面)。
- 监听路由。
- 订阅发布展示内容。
Hash模式
通过hash
改变地址,监听hashchange
事件,判断hash
展示对应地址内容。
- 改变路由
- 浏览器锚点
#
的变化可以被监听,并且hash
改变时不会刷新页面。
- 浏览器锚点
- 监听路由
hashchange
事件,可以监听如下变化:- 点击
a
标签,改变了浏览器地址。 - 浏览器的前进后退行为。
- 通过
window.location
方法,改变浏览器地址。
- 点击
class Router {
routes = {}
currenturl = ''
route(path, callback = () => void 0) {
this.routes[path] = callback
}
refresh() {
console.log('触发hashchange')
const path = location.hash.slice(1) || '/'
this.currenturl = path
if ( this.routes[path] ) {
this.routes[path]()
}
}
init() {
window.addEventListener('load', () => this.refresh(), false)
window.addEventListener('hashchange', () => this.refresh(), false)
}
}
复制代码
缺点:
- 地址栏,不好看
- 想服务端发送请求时,锚点不会在url中携带,页面数据不好监控。
- 锚点功能失效。
History模式
通过url
改变地址,监听popstate
事件,拦截不触发popstate
的跳转方式,判断url
展示对应地址内容。
原理:
- 改变路由
history
的pushState
(跳转)和replaceState
(重定向)可以改变地址,并且不刷新页面。
- 监听路由
popstate
事件 ,判断pathname
地址- 浏览器回退,history.back,history.forward都会触发此事件。
pushState
、replaceState
、a
标签的跳转不会被popstate
监听。- 劫持
pushState
、replaceState
方法,内部在调用原方法。 a
标签- 获取全局
a
标签后添加点击事件 - 提供
Link
组件
- 获取全局
- 劫持
class JSHistoryRouter {
constructor(routerview){
this.routerView = routerview
}
init(){
let that = this
let linkList = document.querySelectorAll('a[href]')
linkList.forEach(el => el.addEventListener('click', function (e) {
e.preventDefault() // 阻止 <a> 默认跳转事件
history.pushState(null, '', el.getAttribute('href')) // 获取 URL,跳转
that.routerView.innerHTML = '当前路由:' + location.pathname
}))
// 监听 URL 改变
window.addEventListener('popstate', ()=>{
this.routerView.innerHTML = '当前路由:' + location.pathname
})
}
push(path){
history.pushState(null, '', path)
this.routerView.innerHTML = '当前路由:' + path
}
replace(path){
history.replaceState(null, '', path)
this.routerView.innerHTML = '当前路由:' + path
}
}
复制代码
缺点:
- 需要nginx做配合,否则会出现404
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END