【高频考点精讲】前端路由原理深度解析:从hash到history API

前端路由原理深度解析:从hash到history API

今天咱们聊聊前端路由那点事儿。作为一个在前后端反复横跳的老司机,全栈老李发现很多同学对路由的理解还停留在”会用vue-router”的层面,这就像只会开车却不懂发动机原理一样危险啊!

为什么需要前端路由?

想象一下你去餐厅吃饭,传统服务端渲染就像每次点菜都要服务员跑后厨问厨师(服务器请求页面),而前端路由则是服务员直接把菜单(数据)给你,你在桌上自己拼装(客户端渲染)。这样切换”菜品”(页面)时就不用每次都麻烦厨师了。

Hash模式:最朴素的解决方案

最早的前端路由方案是hash路由,它的原理简单粗暴:

// 全栈老李提示:这是最基础的hash路由实现
class HashRouter {
            
  constructor() {
            
    this.routes = {
            };
    window.addEventListener('hashchange', this.refresh);
  }
  
  addRoute(path, callback) {
            
    this.routes[path] = callback;
  }
  
  refresh = () => {
            
    const hash = window.location.hash.slice(1) || '/';
    if (this.routes[hash]) {
            
      this.routes[hash]();
    }
  }
}

// 使用示例
const router = new HashRouter();
router.addRoute('/home', () => {
            
  document.getElementById('app').innerHTML = '<h1>首页</h1>';
});
router.addRoute('/about', () => {
            
  document.getElementById('app').innerHTML = '<h1>关于我们</h1>';
});

hash路由的特点:

URL中带#,比如example.com/#/about
改变hash不会触发页面刷新
兼容性好,连IE6都能用

但它的缺点也很明显:URL不够优雅,SEO不友好,而且#后面的内容服务器根本收不到。这就好比用摩斯密码谈恋爱——能沟通但不够体面。

History API:现代前端路由的标配

HTML5带来了History API,终于让我们能优雅地操作URL了。核心是这三个方法:

// 全栈老李的history路由实现示例
class HistoryRouter {
            
  constructor() {
            
    this.routes = {
            };
    this.init();
  }
  
  init() {
            
    window.addEventListener('popstate', this.handlePopState);
    document.addEventListener('click', this.handleLinkClick);
  }
  
  addRoute(path, callback) {
            
    this.routes[path] = callback;
  }
  
  navigate(path) {
            
    history.pushState({
            }, '', path);
    this.dispatch(path);
  }
  
  handlePopState = () => {
            
    const path = window.location.pathname;
    this.dispatch(path);
  }
  
  handleLinkClick = (e) => {
            
    if (e.target.tagName === 'A') {
            
      e.preventDefault();
      this.navigate(e.target.getAttribute('href'));
    }
  }
  
  dispatch(path) {
            
    if (this.routes[path]) {
            
      this.routes[path]();
    }
  }
}

// 使用示例
const router = new HistoryRouter();
router.addRoute('/home', () => {
            
  document.getElementById('app').innerHTML = '<h1>首页</h1>';
});
router.addRoute('/about', () => {
            
  document.getElementById('app').innerHTML = '<h1>关于我们</h1>';
});

History路由的三大法宝:

history.pushState() – 添加历史记录但不刷新页面
history.replaceState() – 替换当前历史记录
popstate事件 – 监听前进后退操作

这就好比给你的网页装上了时光机,可以自由穿梭还不刷新页面。但要注意的是,直接访问history路由的URL会404,因为服务器没有对应的静态资源。解决方案嘛,要么让服务器把所有路由都指向index.html(SSR应用常用),要么配置nginx重定向。

实战中的路由守卫

现代框架的路由都提供了守卫功能,咱们可以自己实现个简易版:

// 全栈老李的路由守卫实现
class GuardedRouter extends HistoryRouter {
            
  constructor(beforeEach) {
            
    super();
    this.beforeEach = beforeEach;
  }
  
  navigate(path) {
            
    this.beforeEach(path, () => {
            
      super.navigate(path);
    });
  }
}

// 使用示例
const router = new GuardedRouter((to, next) => {
            
  console.log(`准备跳转到 ${
              to}`);
  if (to === '/admin') {
            
    alert('无权访问!');
  } else {
            
    next();
  }
});

这个守卫就像夜店门口的保安,不符合条件的统统拦在外面!

面试题时间

来道实战题检验下学习成果(评论区交作业,老李会随机点评哦):

/**
 * 实现一个简易路由解析器
 * 要求:
 * 1. 支持动态参数 /user/:id
 * 2. 返回匹配的参数对象
 * 示例:
 * const router = new Router();
 * router.addRoute('/user/:id', (params) => {
 *   console.log(params.id);
 * });
 * router.dispatch('/user/123'); // 输出123
 * 
 * 全栈老李提示:可以用正则表达式匹配路径
 */
class Router {
            
  constructor() {
            
    this.routes = [];
  }
  
  addRoute(path, handler) {
            
    // 你的代码 here
  }
  
  dispatch(currentPath) {
            
    // 你的代码 here
  }
}

路由选择的艺术

最后聊聊如何选择路由方案:

需要兼容老浏览器?选hash
要做SSR?history是必须的
担心SEO?history+服务端渲染
移动端Hybrid App?hash可能更稳妥

记住全栈老李的忠告:技术选型没有银弹,只有最适合当前场景的方案。就像你不能用筷子吃牛排,也不能用刀叉喝汤对吧?

下次咱们聊聊路由的进阶玩法——路由懒加载和预加载,让你的应用飞起来!评论区见~

🔥 必看面试题

【初级】前端开发工程师面试100题(一)
【初级】前端开发工程师面试100题(二)
【初级】前端开发工程师的面试100题(速记版)

我是全栈老李,一个资深Coder!

写码不易,如果你觉得本文有收获,点赞 + 收藏走一波!感谢鼓励🌹🌹🌹

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容