1.什么是前端路由
官方:路由的概念来源于服务端,在服务端中路由描述的是 URL 与处理函数之间的映射关系。
这是官方的概念 说一下我个人的理解:路由就是根据url中不同的hash值来展示不同的组件。那么此时就会有一下几个核心问题
- 如何改变 URL 却不引起页面刷新? —— url中#后面的称为hash值
如何改变 URL 却不引起页面刷新?
如何检测 URL 变化了?
下面分别使用 hash 和 history 两种实现方式回答上面的两个核心问题。
hash实现:
- 通过hashchange方法监听hash值的变化 通过a标签来控制hash值 通过location.href和a标签都会触发hashchange事件
原生js hash模式实现路由跳转
<body>
<ul>
<!-- 定义路由 通过a标签来控制路由的显示-->
<li><a href="#/home">home</a></li>
<li><a href="#/about">about</a></li>
<!-- 渲染路由对应的 UI -->
<div id="routeView"></div>
</ul>
<script>
// 页面加载完不会触发 hashchange,这里主动触发一次 hashchange 事件
window.addEventListener('DOMContentLoaded', onLoad)
// hash值发生变化就会触发hashchange事件
window.addEventListener('hashchange',HashChange)
function onLoad(){
// 页面加载获取容器
let routerView=document.querySelector('#routeView')
// 获取容器后调用hashchange方法显示不同的内容
HashChange()
}
function HashChange(){
//根据不同的hash值显示不同内容
// location.hash可以获取到url中hash值得内容
switch(location.hash){
case '#/home':
routerView.innerHTML = 'Home'
return
case '#about':
routerView.innerHTML = 'About'
return
}
}
</script>
<body>
此时就可以通过监听hash值的变化来改变显示的内容了
history模式
-
history 提供了 pushState 和 replaceState 两个方法,这两个方法改变 URL 的 path 部分不会引起页面刷新
-
history 提供类似 hashchange 事件的 popstate 事件,但 popstate 事件有些不同:通过浏览器前进后退改变 URL 时会触发 popstate 事件,通过pushState/replaceState或
<a>
标签改变 URL 不会触发 popstate 事件。好在我们可以拦截 pushState/replaceState的调用和<a>
标签的点击事件来检测 URL 变化,所以监听 URL 变化可以实现,只是没有 hashchange 那么方便。
通过history来实现路由功能
<body>
<ul>
<!-- 定义路由 通过a标签来控制路由的显示-->
<ul>
<li><a href='/home'>home</a></li>
<li><a href='/about'>about</a></li>
<div id="routeView"></div>
</ul>
<!-- 渲染路由对应的 UI -->
<div id="routeView">About</div>
</ul>
<script>
// 页面加载完不会触发 hashchange,这里主动触发一次 hashchange 事件
window.addEventListener('DOMContentLoaded', onLoad)
// 监听路由变化
window.addEventListener('popstate', onPopState)
// 路由视图
var routerView = null
function onLoad () {
// 获取容器
routerView = document.querySelector('#routeView')
onPopState()
// 拦截 <a> 标签点击事件默认行为, 点击时使用 pushState 修改 URL并更新手动 UI,从而实现点击链接更新 URL 和 UI 的效果。
var linkList = document.querySelectorAll('a[href]')
linkList.forEach(el => el.addEventListener('click', function (e) {
e.preventDefault()
history.pushState(null, '', el.getAttribute('href'))
onPopState()
}))
}
// 路由变化时,根据路由渲染对应 UI
function onPopState () {
switch (location.pathname) {
case '/home':
routerView.innerHTML = 'Home'
return
case '/about':
routerView.innerHTML = 'About'
return
default:
return
}
}
</script>
</body