在前端单页应用开发中,路由是实现无刷新页面切换的核心能力,很多开发者会问怎样用JavaScript处理路由。其实JavaScript处理路由不需要依赖第三方库,原生就能实现两种主流方案,分别是hash路由和history路由,下面我们逐一讲解。

一、hash路由的实现
hash路由依赖URL中的#后面的hash值变化来触发路由切换,它的优势是兼容性好,所有浏览器都支持,而且hash变化不会触发页面刷新,也不需要服务器做额外配置。
实现原理
我们可以通过监听hashchange事件来捕获hash值的变化,然后根据不同的hash值匹配对应的页面组件进行渲染。
代码示例
// 定义路由映射表,key是hash值,value是对应的渲染函数
const routes = {
'/': function() {
document.getElementById('app').innerHTML = '<h1>首页</h1><p>这是首页内容</p>';
},
'/about': function() {
document.getElementById('app').innerHTML = '<h1>关于我们</h1><p>这是关于页面内容</p>';
},
'/contact': function() {
document.getElementById('app').innerHTML = '<h1>联系我们</h1><p>这是联系页面内容</p>';
}
};
// 路由渲染函数,根据当前hash匹配对应路由
function renderRoute() {
// 获取当前hash,去掉开头的#
const hash = window.location.hash.slice(1) || '/';
// 如果路由不存在,渲染404页面
if (routes[hash]) {
routes[hash]();
} else {
document.getElementById('app').innerHTML = '<h1>404</h1><p>页面不存在</p>';
}
}
// 监听hash变化事件
window.addEventListener('hashchange', renderRoute);
// 页面加载时先执行一次渲染
window.addEventListener('load', renderRoute);二、history路由的实现
history路由基于HTML5提供的history API实现,常用的API有pushState、replaceState和popstate事件,它的URL没有#,看起来更美观,但是需要服务器配合处理页面刷新的问题。
实现原理
我们使用pushState方法修改浏览器的历史记录,同时监听popstate事件来捕获浏览器前进后退操作,再根据当前的路径匹配对应的路由进行渲染。
代码示例
// 定义路由映射表,key是路径,value是对应的渲染函数
const routes = {
'/': function() {
document.getElementById('app').innerHTML = '<h1>首页</h1><p>这是首页内容</p>';
},
'/about': function() {
document.getElementById('app').innerHTML = '<h1>关于我们</h1><p>这是关于页面内容</p>';
},
'/contact': function() {
document.getElementById('app').innerHTML = '<h1>联系我们</h1><p>这是联系页面内容</p>';
}
};
// 路由渲染函数,根据当前路径匹配对应路由
function renderRoute() {
const path = window.location.pathname || '/';
if (routes[path]) {
routes[path]();
} else {
document.getElementById('app').innerHTML = '<h1>404</h1><p>页面不存在</p>';
}
}
// 封装路由跳转函数,使用pushState修改历史记录,不触发页面刷新
function navigateTo(path) {
window.history.pushState({}, '', path);
renderRoute();
}
// 监听浏览器前进后退事件
window.addEventListener('popstate', renderRoute);
// 页面加载时先执行一次渲染
window.addEventListener('load', renderRoute);
// 给页面中的链接绑定跳转事件,阻止默认跳转行为
document.querySelectorAll('a[data-link]').forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
const path = this.getAttribute('href');
navigateTo(path);
});
});三、两种路由方案的对比
我们可以根据实际需求选择合适的路由方案,下面是两种方案的对比:
| 对比项 | hash路由 | history路由 |
|---|---|---|
| URL格式 | 带#,如http://ippipp.com/#/about | 不带#,如http://ippipp.com/about |
| 兼容性 | 兼容所有浏览器 | 兼容IE10及以上浏览器 |
| 服务器配置 | 不需要额外配置 | 需要配置所有路径指向入口文件 |
| 监听事件 | hashchange | popstate |
四、路由参数处理
实际开发中经常需要处理带参数的路由,比如/user/123这样的动态路由,我们可以通过正则匹配的方式来提取路由参数。
动态路由匹配示例
// 定义带参数的路由规则,:id是动态参数
const routes = [
{ path: '/', component: function() { document.getElementById('app').innerHTML = '<h1>首页</h1>'; } },
{ path: '/user/:id', component: function(params) {
document.getElementById('app').innerHTML = `<h1>用户页面</h1><p>用户ID是:${params.id}</p>`;
} }
];
// 匹配路由并提取参数
function matchRoute(path) {
for (let route of routes) {
// 将路由规则转为正则,比如/user/:id转为^/user/([^/]+)$
const regex = new RegExp('^' + route.path.replace(/:(\w+)/g, '([^/]+)') + '$');
const match = path.match(regex);
if (match) {
// 提取参数,match[1]及之后的是动态参数
const paramNames = (route.path.match(/:(\w+)/g) || []).map(name => name.slice(1));
const params = {};
paramNames.forEach((name, index) => {
params[name] = match[index + 1];
});
return { component: route.component, params };
}
}
return null;
}
// 渲染路由的函数
function renderRoute() {
const path = window.location.pathname || '/';
const matched = matchRoute(path);
if (matched) {
matched.component(matched.params);
} else {
document.getElementById('app').innerHTML = '<h1>404</h1>';
}
}以上就是用JavaScript原生处理路由的完整方法,开发者可以根据项目需求选择合适的方案,也可以基于这些原理封装更符合自己项目的路由工具。
JavaScript路由处理前端路由hash路由history路由修改时间:2026-05-29 23:03:32