前端路由
前端路由主要分为两种模式:hash 和 history。
这两种模式都不会触发页面的刷新
Hash模式
hash模式就是用#号将路由的路径拼接在 url 后面,当#号后面的路径发生改变时,会触发 onhashchange 事件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hash 模式</title>
</head>
<body>
<div>
<ul>
<li><a href="#/page1">page1</a></li>
<li><a href="#/page2">page2</a></li>
</ul>
<!--渲染对应组件的地方-->
<div id="route-view"></div>
</div>
<script type="text/javascript">
// 第一次加载的时候,不会执行 hashchange 监听事件,默认执行一次
// DOMContentLoaded 为浏览器 DOM 加载完成时触发
window.addEventListener('DOMContentLoaded', Load)
window.addEventListener('hashchange', HashChange)
// 展示页面组件的节点
var routeView = null
function Load() {
routeView = document.getElementById('route-view')
HashChange()
}
function HashChange() {
// 每次触发 hashchange 事件,通过 location.hash 拿到当前浏览器地址的 hash 值
// 根据不同的路径展示不同的内容
switch(location.hash) {
case '#/page1':
routeView.innerHTML = 'page1'
return
case '#/page2':
routeView.innerHTML = 'page2'
return
default:
routeView.innerHTML = 'page1'
return
}
}
</script>
</body>
</html>
History模式
- 监听路由
History模式提供了popstate事件。当 history 对象出现变化时,就会触发 popstate 事件。
- 改变路由
1) history.pushState(state,title,path)
- state: popstate 事件触发时,该对象会传入回调函数
- title:新页面的标题
- path:新的网址,必须与当前页面处在同一个域。浏览
2)history.replaceState(state,title,path)
用 history.pushState() 或者 history.replaceState() 不会触发 popstate 事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>History 模式</title>
</head>
<body>
<div>
<ul>
<li><a href="/page1">page1</a></li>
<li><a href="/page2">page2</a></li>
</ul>
<div id="route-view"></div>
</div>
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', Load)
window.addEventListener('popstate', PopChange) //监听回退和前进
var routeView = null
function Load() {
routeView = document.getElementById('route-view')
// 默认执行一次 popstate 的回调函数,匹配一次页面组件
PopChange()
// 获取所有带 href 属性的 a 标签节点
var aList = document.querySelectorAll('a[href]')
// 遍历 a 标签节点数组,阻止默认事件,添加点击事件回调函数
aList.forEach(aNode => aNode.addEventListener('click', function(e) {
e.preventDefault() //阻止a标签的默认事件
var href = aNode.getAttribute('href')
// 手动修改浏览器的地址栏
history.pushState(null, '', href)
// 通过 history.pushState 手动修改地址栏,
// popstate 是监听不到地址栏的变化,所以此处需要手动执行回调函数 PopChange
PopChange()
}))
}
function PopChange() {
console.log('location', location)
switch(location.pathname) {
case '/page1':
routeView.innerHTML = 'page1'
return
case '/page2':
routeView.innerHTML = 'page2'
return
default:
routeView.innerHTML = 'page1'
return
}
}
</script>
</body>
</html>