前端路由原理:让单页面应用跳转如丝般顺滑
前言
今天来聊聊单页面应用(SPA)的核心技术——前端路由。你有没有想过,为什么现在很多网站跳转页面时不刷新了?为什么URL变了但内容切换得这么流畅?这一切都要归功于前端路由!今天就带你彻底搞懂它的实现原理,保证让你收获满满!
利用URL的Hash(#)
最古老但最简单的方法就是利用URL中的hash(就是#号后面的部分)。浏览器有个特点:改变hash不会重新加载页面,但会留下历史记录。
// 改变hash
window.location.hash = '/home';
// 监听hash变化
window.addEventListener('hashchange', function() {
console.log('Hash变了!现在是:', window.location.hash);
});
这种方法兼容性好,连IE8都支持!但缺点就是URL里总是带着个#号,看起来不太美观。
import 方式
早年还有人用import的方式实现"模块化"加载,但现在基本被淘汰了:
// 古老的方式,了解一下就行
const importPage = (url) => {
document.write('<script type="text/javascript" src="' + url + '"></script>');
};
这种方法现在基本没人用了,知道有这么回事就行。
AJAX 方式
Ajax出现后,我们可以无刷新获取内容了:
function loadPage(url) {
fetch(url)
.then(response => response.text())
.then(html => {
document.getElementById('content').innerHTML = html;
});
}
但这样有个问题:URL没变,用户没法直接分享或收藏特定页面。所以还需要配合其他技术来实现真正的路由。
利用 H5 新增方法 History interface
HTML5给我们带来了更优雅的解决方案——History API。这才是现代前端路由的标配!
往返缓存
浏览器为了提升性能,会把之前访问的页面缓存起来(叫做bfcache)。当你点击后退按钮时,页面会从缓存中快速加载,而不是重新请求。
往历史记录栈中添加记录:pushState(state, title, url)
这个方法可以在不刷新页面的情况下改变URL,并添加历史记录:
// 添加新历史记录
history.pushState({page: 1}, "首页", "/home");
参数说明:
- state:一个状态对象,与新历史记录相关联
- title:目前大多数浏览器忽略这个参数(但必须传)
- url:新的URL(必须是同源的)
改变当前的历史记录:replaceState(state, title, url)
和pushState类似,但不是添加新记录,而是替换当前记录:
// 替换当前历史记录
history.replaceState({page: 2}, "关于", "/about");
history.state
这个属性可以获取当前历史记录条目的状态对象:
console.log(history.state); // 输出当前状态对象
popstate
当用户点击浏览器前进/后退按钮时,会触发popstate事件:
window.addEventListener('popstate', function(event) {
// event.state 包含pushState或replaceState时传入的state对象
console.log('位置变了:', event.state);
});
实现
现在我们来手写一个简单的前端路由:
class SimpleRouter {
constructor() {
this.routes = {};
this.bindEvents();
}
// 添加路由
addRoute(path, callback) {
this.routes[path] = callback;
}
// 跳转到指定路径
navigate(path) {
history.pushState({path}, null, path);
this.executeRoute(path);
}
// 执行路由对应的回调
executeRoute(path) {
if (this.routes[path]) {
this.routes[path]();
} else {
console.error('路由不存在:', path);
}
}
// 绑定事件监听
bindEvents() {
// 监听popstate事件(前进/后退)
window.addEventListener('popstate', (event) => {
if (event.state && event.state.path) {
this.executeRoute(event.state.path);
}
});
// 监听链接点击(阻止默认行为,使用路由导航)
document.addEventListener('click', (e) => {
if (e.target.tagName === 'A' && e.target.getAttribute('href')) {
e.preventDefault();
this.navigate(e.target.getAttribute('href'));
}
});
}
}
// 使用示例
const router = new SimpleRouter();
router.addRoute('/home', () => {
document.getElementById('content').innerHTML = '<h1>首页内容</h1>';
});
router.addRoute('/about', () => {
document.getElementById('content').innerHTML = '<h1>关于我们</h1>';
});
// 初始化
router.navigate('/home');
总结
前端路由让单页面应用成为了可能,提供了更流畅的用户体验。现在你知道了吧:
- Hash方式简单兼容性好,但URL不美观
- History API是现代SPA的首选,URL干净美观
- pushState/replaceState改变URL但不刷新页面
- popstate监听前进后退操作
- 实际实现需要结合路由表和事件监听
现在的主流框架(Vue Router、React Router)都是基于这些原理实现的,只是加了更多功能和优化。理解了这些底层原理,你再使用这些框架时就会得心应手了!