以下是如何使用 JavaScript 实现一个简单前端路由的完整指南,结合核心原理、实现步骤和实际代码示例:
一、前端路由的核心原理
前端路由的本质是监听 URL 变化 → 解析路径 → 匹配规则 → 动态渲染内容,避免页面刷新。实现方式分为两种模式:
-
Hash 模式
- 利用 URL 中
#
后的部分(如[http://site.com/#/about](http://site.com/#/about)
) - 优势:兼容性好(支持 IE8+),改变 hash 不会触发页面请求
- 监听事件:
hashchange
- 利用 URL 中
-
History 模式
- 基于 HTML5 History API(
pushState()
/replaceState()
) - 优势:URL 更简洁(如
[http://site.com/about](http://site.com/about)
),SEO 友好 - 监听事件:
popstate
(需手动处理导航)
- 基于 HTML5 History API(
✅ 关键区别:
- Hash 模式:服务器无需特殊配置,仅
#
前的内容会发送到后端- History 模式:需服务器支持(如 Nginx 配置
try_files $uri $uri/ /index.html
),否则直接访问子路由会返回 404
二、手写路由的完整实现步骤
步骤 1:监听 URL 变化
Hash 模式:
window.addEventListener('hashchange', () => {
const hash = location.hash.slice(1) || '/'; // 去掉#,默认根路径
handleRouteChange(hash);
});
History 模式:
window.addEventListener('popstate', () => {
const path = location.pathname || '/';
handleRouteChange(path);
});
步骤 2:解析 URL 并匹配路由
const routes = {
'/': HomeComponent,
'/about': AboutComponent,
'/user/:id': UserComponent // 动态路由
};
function handleRouteChange(path) {
// 1. 静态路由匹配
if (routes[path]) {
renderComponent(routes[path]);
return;
}
// 2. 动态路由匹配(如 /user/123)
const dynamicPaths = Object.keys(routes).filter(key => key.includes(':'));
for (const route of dynamicPaths) {
const regex = new RegExp(`^${route.replace(/:\w+/g, '(\\w+)')}$`);
const match = path.match(regex);
if (match) {
const params = { id: match[1] }; // 提取参数
renderComponent(routes[route], params);
return;
}
}
// 3. 未匹配时渲染 404
renderComponent(NotFoundComponent);
}
步骤 3:实现导航功能
Hash 模式导航:
function navigateTo(path) {
location.hash = `#${path}`;
}
History 模式导航:
function navigateTo(path) {
history.pushState({}, '', path); // 修改 URL 不刷新页面
handleRouteChange(path); // 手动触发路由处理
}
步骤 4:内容渲染与动态加载
function renderComponent(component, params = {}) {
const app = document.getElementById('app');
// 动态加载组件(懒加载)
if (typeof component === 'function') {
component().then(comp => app.innerHTML = comp(params));
}
// 直接渲染组件
else {
app.innerHTML = component(params);
}
}
// 示例:懒加载组件
const AboutComponent = () => import('./views/About.js');
三、进阶功能实现
1. 路由守卫(权限控制)
router.beforeEach = (to, from, next) => {
if (to.path === '/admin' && !isLoggedIn()) {
next('/login'); // 跳转到登录页
} else {
next(); // 放行
}
};
// 在 handleRouteChange 中调用守卫
handleRouteChange(path).then(() => {
router.beforeEach(currentPath, prevPath, next);
});
2. 嵌套路由实现
const routes = {
'/user': {
component: UserLayout,
children: [
{ path: '/profile', component: Profile },
{ path: '/settings', component: Settings }
]
}
};
// 渲染时递归查找子路由
function resolveNestedRoute(path, routes) {
// ...递归匹配逻辑
}
3. 路径匹配优化
- 正则表达式匹配:用
path-to-regexp
库高效处理动态路径 - 前缀树(Trie) :Gin 框架使用的算法,适合大规模路由
四、两种模式的完整代码示例
Hash 模式基础实现
<div id="app"></div>
<script>
const routes = {
'/': '<h1>Home Page</h1>',
'/about': '<h1>About Us</h1>'
};
window.addEventListener('hashchange', () => {
const path = location.hash.substring(1) || '/';
document.getElementById('app').innerHTML = routes[path] || '<h1>404 Not Found</h1>';
});
// 初始化加载
window.dispatchEvent(new Event('hashchange'));
</script>
History 模式进阶实现
class Router {
constructor() {
this.routes = {};
this.bindEvents();
}
addRoute(path, component) {
this.routes[path] = component;
}
bindEvents() {
window.addEventListener('popstate', this.handlePopState.bind(this));
document.addEventListener('click', e => {
if (e.target.tagName === 'A') {
e.preventDefault();
this.navigate(e.target.href);
}
});
}
navigate(path) {
history.pushState({}, '', path);
this.handleRouteChange();
}
handlePopState() {
this.handleRouteChange();
}
handleRouteChange() {
const path = window.location.pathname;
const component = this.routes[path] || this.routes['/404'];
document.getElementById('app').innerHTML = component();
}
}
// 使用示例
const router = new Router();
router.addRoute('/', () => '<h1>Home</h1>');
router.addRoute('/about', () => '<h1>About</h1>');
五、生产环境注意事项
1.History 模式服务器配置
Nginx 示例:
location / {
try_files $uri $uri/ /index.html;
}
2.性能优化
路由懒加载:用 import()
动态加载组件
const About = () => import('./About.vue');
3.SEO 处理
- History 模式 + 服务端渲染(SSR)解决 SPA 的 SEO 问题
4.错误边界
- 监听未匹配路由并显示 404 页面
选型建议:
- 兼容旧浏览器 → Hash 模式
- 新项目 + 需要友好 URL → History 模式
通过以上实现,可构建一个支持动态参数、嵌套路由、懒加载的完整前端路由系统。实际开发推荐使用 Vue Router 或 React Router 等成熟库,但理解底层原理对解决复杂问题至关重要 。