前端路由原理
路由的概念来源于服务端,描述URL与处理函数之间的映射关系。
在web前端单页应用SPA中,路由描述URL与UI之间的映射关系,这种映射是单向的,即URL变化引起UI更新(无需刷新页面)。
要实现前端路由,需要解决两个核心:
- 如何改变URL却不引起页面刷新?
- 如何检测URL变化?
hash
实现
hash
是URL中hash(#)
及后面的部分,常用作锚点在页面内进行导航,改变URL中的hash
部分不会引起页面刷新- 通过
hashchange
事件监听URL的变化,改变URL的方式只有这几种:- 通过浏览器前进后退改变URL
- 通过
<a>
标签改变URL - 通过
window.location
改变URL
history
实现
history
提供了pushState
和replaceState
两种方法,这两种方法改变URL的path
部分不会引起页面刷新history
提供类似hashchange
事件的popstate
事件,但popstate
事件有些不同- 通过浏览器前进后退改变URL时会触发
popstate
事件 - 通过
pushState/replaceState
或<a>
标签改变URL不会触发popstate
事件 - 可以拦截
pushState/replaceState
的调用和<a>
标签的点击事件来检测URL变化,所以监听URL变化可以实现,只是没有hashchange
那么方便
- 通过浏览器前进后退改变URL时会触发
原生JS前端路由实现
基于hash
实现
<ul>
<li><a href="#/home">home</a></li>
<li><a href="#/about">about</a></li>
</ul>
<div id="routeView"></div>
//页面加载完不会触发hashchange,这里主动触发一次hashchange事件
window.addEventListener('DOMContentLoaded', onload);
//监听路由变化
window.addEventListener('hashchange', onHashChange);
//路由视图
var routerView = null;
function onload() {
routerView = document.querySelector('#routeView');
onHashChange();
}
//路由变化时,根据路由渲染对应UI
function onHashChange() {
switch (location.hash) {
case '#/home':
routerView.innerHTML = 'Home';
return;
case '#/about':
routerView.innerHTML = 'About';
return;
default:
return;
}
}
基于history
实现
<ul>
<li><a href="/home">home</a></li>
<li><a href="/about">about</a></li>
</ul>
<div id="routeView"></div>
//页面加载完不会触发hashchange,这里主动触发一次hashchange事件
window.addEventListener('DOMContentLoaded', onload);
//监听路由变化
window.addEventListener('hashchange', 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', (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;
}
}
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。