前言
单页面应用(SPA)中那个必问的前端路由原理。别说你没被问过这个问题,除非你还没参加过前端面试!掌握了这个,不仅能轻松应对面试,更能让你在实际开发中游刃有余。准备好了吗?咱们开始!
1. 什么是前端路由?
简单来说,前端路由就是让页面不刷新却能切换内容的神奇技术。就像变魔术一样,URL变了,内容也变了,但页面完全没有重新加载!
传统网站:点击链接 → 页面刷新 → 显示新内容
SPA网站:点击链接 → URL变化 → JS切换内容 → 完事!
2. 两种实现方式
2.1 Hash模式(#号大法)
这是最经典的方式,利用URL中的hash(#号后面的部分):
// 改变hash不会导致页面刷新
window.location.hash = '/home';
// 监听hash变化
window.addEventListener('hashchange', () => {
const path = window.location.hash.slice(1); // 去掉#
renderContent(path); // 根据路径渲染内容
});
面试要点:
- ✅ 兼容性好(IE8都支持)
- ✅ 实现简单
- ❌ URL不太美观(总是带着#)
2.2 History模式(H5新特性)
HTML5带来了更优雅的History API:
// 添加历史记录但不刷新页面
history.pushState({}, '', '/home');
// 监听前进后退
window.addEventListener('popstate', (event) => {
const path = window.location.pathname;
renderContent(path);
});
面试要点:
- ✅ URL美观(没有#)
- ✅ 功能更强大
- ❌ 需要服务端配合(避免404)
- ❌ 兼容性稍差(IE10+)
3. 手写简易路由实现
面试官最爱让你手写代码了,来,看这个:
class MiniRouter {
constructor(mode = 'hash') {
this.routes = {};
this.mode = mode;
this.init();
}
// 初始化
init() {
if (this.mode === 'hash') {
window.addEventListener('hashchange', () => this.handleChange());
this.handleChange(); // 初始处理
} else {
window.addEventListener('popstate', () => this.handleChange());
// 拦截链接点击
document.addEventListener('click', (e) => {
if (e.target.tagName === 'A') {
e.preventDefault();
this.navigate(e.target.getAttribute('href'));
}
});
}
}
// 添加路由
addRoute(path, callback) {
this.routes[path] = callback;
}
// 导航
navigate(path) {
if (this.mode === 'hash') {
window.location.hash = '#' + path;
} else {
history.pushState({}, '', path);
this.handleChange();
}
}
// 处理路由变化
handleChange() {
let path;
if (this.mode === 'hash') {
path = window.location.hash.slice(1) || '/';
} else {
path = window.location.pathname;
}
if (this.routes[path]) {
this.routes[path]();
} else {
this.routes['/404']?.(); // 调用404页面
}
}
}
// 使用示例
const router = new MiniRouter('history');
router.addRoute('/', () => console.log('首页'));
router.addRoute('/about', () => console.log('关于页'));
4. 面试常问问题
4.1 Hash和History模式有什么区别?
| 特性 | Hash模式 | History模式 |
|---|---|---|
| URL美观度 | 有#号,不太美观 | 无#号,美观 |
| 兼容性 | IE8+ | IE10+ |
| 服务端配置 | 不需要特殊配置 | 需要配置支持 |
| SEO | 相对较差 | 相对较好 |
4.2 为什么History模式需要服务端配置?
因为如果你直接访问/about这样的路径,服务端可能没有这个真实路径,就会返回404。解决方案是让服务端把所有路由都指向index.html,让前端路由来处理。
4.3 如何实现路由守卫?
// 简单的路由守卫实现
class RouterWithGuard extends MiniRouter {
constructor() {
super();
this.beforeEachHooks = [];
}
beforeEach(callback) {
this.beforeEachHooks.push(callback);
}
navigate(path) {
// 执行所有守卫
let shouldProceed = true;
for (const hook of this.beforeEachHooks) {
if (hook(path) === false) {
shouldProceed = false;
break;
}
}
if (shouldProceed) {
super.navigate(path);
}
}
}
5. 实战技巧
5.1 路由懒加载
// 动态导入实现懒加载
router.addRoute('/settings', () => {
import('./Settings.js').then(module => {
module.default(); // 渲染设置页面
});
});
5.2 路由参数解析
// 支持动态参数的路由
router.addRoute('/user/:id', (params) => {
console.log('用户ID:', params.id);
});
// 在handleChange中需要添加参数解析逻辑
6. 总结
前端路由是SPA的核心技术,面试必问!记住这几个关键点:
- 两种模式:Hash简单兼容性好,History美观但需要服务端配合
- 核心API:hashchange、pushState、popstate
- 实现思路:路由表 + 事件监听 + 内容渲染
- 进阶功能:路由守卫、懒加载、参数解析