路由跳转是很典型的命令模式,设计者不知道开发者需要什么路径(请求的接收者),路径对应的页面是什么(被请求的操作),所以设计者提供路由命令给开发者去设置,从而分离路径和跳转页面两个对象。
温馨提示:
npm 安装 http-server
使用http-server开启服务跑history模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
<h3>history 路由</h3>
<a href="/">首页</a>
<a href="/list">用户列表</a>
<a href="/my">关于我们</a>
<a href="">其他</a>
</div>
<div>
<h3>hash 路由</h3>
<a href="#">首页</a>
<a href="#list">用户列表</a>
<a href="#my">关于我们</a>
<a href="">其他</a>
</div>
<script>
const Router = {
base: {
routes: [],
route(path, cb) {
this.routes[path] = cb || function() {}
}
},
history: {
go(path) {
if(!Object.keys(this.routes).includes(path)) path = '/'
window.history.pushState({path}, null, path)
this.routes[path]()
}
},
hash:{
startListenEvent() {
window.addEventListener('load', this.refresh.bind(this))
window.addEventListener('hashchange', this.refresh.bind(this))
},
refresh() {
const path = `/${window.location.hash.slice(1)||''}`
this.routes[path]()
},
},
start(mode) {
let router = Object.assign(this[mode], this.base)
if(mode === 'hash') {
router.startListenEvent()
}
return router
}
}
// history
let router = Router.start('history')
router.route('/', () => console.log('首页'))
router.route('/my', () => console.log('我的'))
router.route('/list', () => console.log('列表'))
console.log(router.routes)
document.querySelectorAll('a').forEach(el => {
el.addEventListener('click', function(e) {
let href = e.target.getAttribute('href')
router.go(href)
e.preventDefault()
})
})
// hash
let router2 = Router.start('history')
router2.route('#', () => console.log('首页hash'))
router2.route('#list', () => console.log('列表hash'))
router2.route('#my', () => console.log('我的hash'))
</script>
</body>
</html>