2021/02/09 - 前端路由的实现原理
lxinr opened this issue · 0 comments
lxinr commented
hash模式
hash值的改变不会向服务端发送请求,hash的改变会触发hashchange事件,浏览器的前进后退也能对其进行控制
基本实现:
export default class HashRouter {
constructor() {
// 使用一个map来保存路由信息
this.routers = new Map()
this._listener()
}
// 监听路由变动
_listener() {
const _handler = this.handler.bind(this)
window.addEventListener('hashchange',_handler,false)
// 模拟注册完成之后执行一次,用于index
setTimeout(() => {
_handler()
}, 0)
}
// 注册路由
register(hash = '', callback) {
this.routers.set(hash, callback)
}
// 注册路由首页
registerIndex(callback) {
this.routers.set('index', callback)
}
// 注册404页
registerNotFound(callback) {
this.routers.set('404', callback)
}
// 用于执行回调函数
handler() {
const hash = location.hash.slice(1)
let cb
if(hash) {
if(!this.routers.has(hash)) {
cb = this.routers.get('404')
} else {
cb = this.routers.get(hash)
}
} else {
cb = this.routers.get('index')
}
cb.call(this)
}
}测试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>hash路由</title>
<style>
#app {
margin: 15px 0;
box-sizing: border-box;
width: 100%;
padding: 15px;
border: 1px solid #696969;
height: 200px;
}
</style>
</head>
<body>
<header>
<a href="#page1">page1</a>
<a href="#page2">page2</a>
<a href="#page3">page3</a>
<a href="#page4">page4</a>
</header>
<section id="app">
</section>
<script type="module">
import HashRouter from './hashRouter/router.mjs'
window.addEventListener('load', () => {
const router = new HashRouter()
const app = document.getElementById('app')
const routes = [
{ path: 'page1', cb: () => app.innerHTML = '这是page1'},
{ path: 'page2', cb: () => app.innerHTML = '这是page2'},
{ path: 'page3', cb: () => app.innerHTML = '这是page3'}
]
routes.forEach(item => {
router.register(item.path, item.cb)
})
router.registerIndex(() => app.innerHTML = '这是首页呀呀呀')
router.registerNotFound(() => app.innerHTML = '找不到你要的页面')
})
</script>
</body>
</html>history模式
history对象提供了对浏览器的会话历史的访问
-
使用
back()(向后跳转),forward()(向前跳转)和go()(指定跳转)方法来完成在用户历史记录中向后和向前的跳转 -
history.pushState()和history.replaceState()可以改变url,且不会刷新页面,其中history.pushState()为向现有历史记录中添加一条新的记录,history.replaceState()为替换当前页面的历史记录,且都会触发popstate事件 -
通过监听
popstate事件来获知history变动
// state - 合法的 Javascript 对象,可以用在 popstate 事件中
// title - 当前大多数浏览器都会忽略的参数,可用null代替
// url - 有效的url,新URL必须与当前URL同源,否则会有异常,用于更新浏览器的地址栏
history.pushState(state, title[, url])
history.replaceState(state, title[, url])