路由的概念来源于服务端,描述URL与处理函数之间的映射关系。
在web前端单页应用SPA中,路由描述URL与UI之间的映射关系,这种映射是单向的,即URL变化引起UI更新(无需刷新页面)。
要实现前端路由,需要解决两个核心:
hash实现
hash是URL中hash(#)及后面的部分,常用作锚点在页面内进行导航,改变URL中的hash部分不会引起页面刷新hashchange事件监听URL的变化,改变URL的方式只有这几种:<a>标签改变URLwindow.location改变URLhistory实现
history提供了pushState和replaceState两种方法,这两种方法改变URL的path部分不会引起页面刷新history提供类似hashchange事件的popstate事件,但popstate事件有些不同popstate事件pushState/replaceState或<a>标签改变URL不会触发popstate事件pushState/replaceState的调用和<a>标签的点击事件来检测URL变化,所以监听URL变化可以实现,只是没有hashchange那么方便原生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;
}
}