前端学习JS手搓简单前端路由
Juns手搓简单前端路由
前言
在学习vue-router
的时候我们就有了解过,前端路由的俩中模式:hash 和 history,那么这里我们就分别用这俩种方法来手写实现一个路由看看。
Hash 模式
在写之前,我们先了解一下以前 hash 是怎么用的。hash 可以用于页面内锚点定位,比如<a href="#title">title</a>
,点击这个链接不会刷新页面,而是浏览器滚动到相应的位置。
其实 Hash 模式就是利用的这个特点,使得 SPA 应用控制路由时,不刷新页面,然后拦截 hash 的变化来切换页面。不过也带来了缺点,无法使用锚点定位了。
所以说我们的目的也就是俩个:
- 修改 url,并且同时需要保证不刷新页面
- 监听 url 变化,作出处理
在 hash 模式中,可以通过 a 标签来做到 1,浏览器也提供了onhashchange
这个 API 来监听 hash 变化,所以我们可以写出如下代码
不过还有一个问题,刚进入页面时,没有内容,可以添加一个DOMContentLoaded
事件处理就可以
<ul> <li><a href="#/home">home</a></li> <li><a href="#/about">about</a></li> </ul>
<div id="routeView"></div>
<script> const routes = [ { path: '#/home', component: 'homePage' }, { path: '#/about', component: 'aboutPage' }, ] const routerView = document.getElementById('routeView')
const router = () => { const currentPath = window.location.hash const route = routes.find(route => route.path === currentPath) if (route) { routerView.innerHTML = route.component } else { routerView.innerHTML = 'homePage' } }
window.addEventListener('DOMContentLoaded', router) window.addEventListener('hashchange', router) </script>
|
History 模式
当 a 链接的 href 属性里面不是 hash 时,会触发页面刷新,那么 history 该如何处理这个问题?以及他怎么监听 url 变化?
在 api 里面都提供了相应的功能,改变 url 可以使用pushState
等,监听可以使用onpopstate
。下面实现看看:
<ul> <li><a href="/home">home</a></li> <li><a href="/about">about</a></li> </ul>
<div id="routeView"></div>
<script> const routes = [ { path: '/home', component: 'homePage' }, { path: '/about', component: '<h1>aboutPage</h1>' }, ] const routerView = document.getElementById('routeView')
const router = () => { const currentPath = window.location.pathname const route = routes.find(route => route.path === currentPath) if (route) { routerView.innerHTML = route.component } else { routerView.innerHTML = 'homePage' } }
const initRoute = () => { const links = document.querySelectorAll('a') links.forEach(link => { link.addEventListener('click', e => { e.preventDefault() window.history.pushState({}, '', e.target.href) router() }) }) }
window.addEventListener('DOMContentLoaded', initRoute) window.onpopstate = router </script>
|
不过他也有一些缺陷,在我们本地掩饰的时候,可能会发现,切换路由后刷新就有可能提示找不到资源,这其实也需要服务端配置路由。