网页url组成部分
获取方式
1. H5 Hash路由
1.1 hash的特点:
- hash变化会 触发网页跳转,即浏览器的前进、后退;
- hash 变化不会刷新页面,SPA必需的特点;
- hash 永远不会提交到 server 端(前端自生自灭)
1.2 hash 变化方式
- JS 修改 url
- 手动修改 url 的 hash
- 浏览器前进、后退
1.3 hash 代码实现
<button id="btn1">修改 hash</button>
...
window.onhashchange = (event) => {
console.log('old url', event.oldURL)
console.log('new url', event.newURL)
console.log('hash:', location.hash)
}
// 页面初次加载,获取 hash
document.addEventListener('DOMContentLoaded', () => {
console.log('hash:', location.hash)
})
// JS 修改 url
document.getElementById('btn1').addEventListener('click', () => {
location.href = '#/user'
})
2. H5 History 路由
- url 规范的路由,但是跳转时不刷新页面
- history.pushState
- window.onpopstate
2.1 正常的页面浏览
- github.com/xxx 刷新页面
- github.com/xxx/yyy 刷新页面
- github.com/xxx/yyy/zzz 刷新页面
2.2 改造成H5 history 路由
- github.com/xxx 刷新页面
- github.com/xxx/yyy 前端跳转,不刷新页面
- github.com/xxx/yyy/zzz 前端跳转,不刷新页面
2.3 H5 history 代码实现
-
设置
history.pushState(state, '', 'page1') -
监听
window.onpopstate=()=>{} -
页面初次加载,获取
document.addEventListener('DOMContentLoaded',()=>{}) -
history,需要 server 端配合,可参考
<p>history API test</p>
<button id="btn1">修改 url</button>
...
<script>
// 页面初次加载,获取 path
document.addEventListener('DOMContentLoaded', () => {
console.log('load', location.pathname)
})
// 打开一个新的路由
// 【注意】用 pushState 方式,浏览器不会刷新页面
document.getElementById('btn1').addEventListener('click', () => {
const state = { name: 'page1' }
console.log('切换路由到', 'page1')
history.pushState(state, '', 'page1') // 重要!!
})
// 监听浏览器前进、后退
window.onpopstate = (event) => { // 重要!!
console.log('onpopstate', event.state, location.pathname)
}
</script>
2.4 可以拦截 a 标签的点击事路由实现
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,跳转
onPopState()
}))
// 监听 URL 改变
window.addEventListener('popstate', onPopState)
}
push(path){
history.pushState(null, '', path)
onPopState()
}
replace(path){
history.replaceState(null, '', path)
onPopState()
}
// 路由变化时,根据路由渲染对应 UI
function onPopState () {
switch (location.pathname) {
case '/home':
routerView.innerHTML = 'Home'
return
case '/about':
routerView.innerHTML = 'About'
return
default:
return
}
}
}
3. 总结
| hash | H5 history | |
|---|---|---|
| 监听 | window.onhashchange | window.onpopstate |
| 设置 | location.href = '#/user' | history.pushState |
| 需要支持 | 无 | 需要后端支持(将所有的路由拦截返回 index.html) |
3.1 两者选择
- TO B 的系统推荐使用hash,简单易用,对url 规范不敏感
- TO C 的系统,可以考虑H5 history,但需要服务器支持
- 能选择简单的,就别用复杂的,要考虑成本和收益
[题外话] react-router支持三种
- BrowserRouter,控制浏览器真实地址的 history 对象
- HashHistory, 控制浏览器 hash 的 history 对象
- StaticRouter, 控制内存中地址的
[题外话] history 对象
- 使用的是history库。 push,go,goBack, goForward操作的支持。
- BrowserRouter和HashHistory调用的浏览器的history对象
- StaticRouter会在内存中维护一个地址栈。支持 push,go,goBack, goForward操作[存疑?]