手撕Hash路由:从面试翻车到源码王者之路 🚀

引言

程序员面对屏幕抓狂

一、那个让我血压升高的面试现场 ⚡

"小明同学,能讲讲前端路由的实现原理吗?" 面试官推了推金丝眼镜,嘴角微微上扬。

我表面稳如老狗,内心慌得一批:"路由嘛,就是...那个...通过监听URL变化加载不同内容?"

"那手写一个Hash路由试试?" 面试官的笑容逐渐变态。

此刻我的CPU开始疯狂运转:Hash路由的组成要素是啥?事件监听怎么绑定?路由表用对象还是数组?脑子里突然蹦出曾经背过的八股文知识点,却像被猫玩乱的毛线球一样纠缠不清... 😿

三十分钟后,我交出了一份漏洞百出的代码,面试官的表情仿佛在说"就这?"。这次惨痛经历让我痛定思痛------是时候彻底征服这个前端必考题了!


背景知识

零、先来补个课:什么是哈希路由?🔍

在开始前可能有部分同学不知道哈希路由是什么? 我们可以来到掘金打开某位大佬的文章: 看到右边的目录:


我们可以试着点一点这各个模块

我们可以看到这上面的路由从

变成了:

这个#/*******就是我们说的哈希值 (Hash),也叫锚点。它最初的设计是用来跳转到页面内的特定位置(就像书签一样),但是!前端大佬们发现了它的隐藏用法:

神奇特性

修改#后面的内容不会触发页面刷新 !(但会新增历史记录)

这意味着我们可以通过监听这个值的变化,实现无刷新页面切换------这就是哈希路由的核心魔法!✨


二、解剖Hash路由:原来你是这样的变色龙 🦎

2.1 为什么选择Hash路由?

先来点硬核知识开胃菜:

  1. 兼容性之王:支持IE8等上古浏览器(虽然现在用的人不多)
  2. SPA救星:改变hash不会触发页面刷新
  3. 监控简单 :一个hashchange事件全搞定
  4. 服务端无痛:不需要服务端特殊配置

2.2 核心实现原理脑图

graph TD A[初始化路由表] --> B[监听hashchange事件] B --> C{当前hash是否存在} C -->|存在| D[执行对应回调] C -->|不存在| E[执行默认回调或404]

三、手把手实现:从青铜到王者的进化之路 👑

3.1 基础版代码实现(含逐行解析)

javascript 复制代码
class HashRouter {
    constructor() {
        this.routes = {}; // 路由登记簿
        window.addEventListener('load', this.load.bind(this)); // 首次加载监听
        window.addEventListener('hashchange', this.load.bind(this)); // 哈希变化监听
    }

    // 注册普通路由
    register(path, callback = () => {}) {
        this.routes[path] = callback; // 把路由存入"通讯录"
    }

    // 注册首页
    registerIndex(callback = () => {}) {
        this.routes['/index'] = callback; // 特殊待遇的首页
    }

    // 核心调度方法
    load() {
        const hash = location.hash.slice(1); // 去掉#号
        let handler;
        
        if (!hash) { // 空路径走首页
            handler = this.routes['/index'];
        } else if (this.routes[hash]) { // 正常路由
            handler = this.routes[hash];
        } else { // 404处理
            handler = () => { container.innerHTML = '404 页面走丢了!' };
        }
        
        handler.call(this); // 执行对应回调
    }
}

关键点解析

  1. location.hash.slice(1):获取#后的路径,比如#/page1得到/page1
  2. 双保险的事件监听:页面加载时和hash变化时都要触发
  3. 路由表使用对象存储:实现O(1)时间复杂度查找

实现效果

3.2 常见翻车现场 🚑

坑1:this指向问题

javascript 复制代码
// 错误示范
window.addEventListener('hashchange', this.load); // this会指向window!

// 正确姿势
window.addEventListener('hashchange', this.load.bind(this));

坑2:重复注册问题

javascript 复制代码
// 如果多次注册同一个路由...
router.register('/page1', () => console.log('第一次'));
router.register('/page1', () => console.log('第二次'));

// 解决方案:注册前先检查
register(path, callback) {
    if(this.routes[path]) {
        console.warn(`重复注册路由:${path}`);
    }
    this.routes[path] = callback;
}

四、给路由加点黑科技 🔥

4.1 动态路由支持

javascript 复制代码
// 支持形如 /user/:id 的路由
register('/user/:id', (params) => {
    console.log(`用户ID:${params.id}`);
});

// 在load方法中增加路径解析
const match = Object.keys(this.routes).find(key => {
    const routePath = key.replace(/:\w+/g, '\\w+');
    return new RegExp(`^${routePath}$`).test(hash);
});

4.2 路由守卫

javascript 复制代码
class HashRouter {
    constructor() {
        this.beforeHooks = [];
    }

    beforeEach(callback) {
        this.beforeHooks.push(callback);
    }

    load() {
        // 执行守卫钩子
        const next = () => {
            // 原有逻辑...
        };
        this.runQueue(this.beforeHooks, next);
    }

    runQueue(queue, fn) {
        const step = index => {
            if (index >= queue.length) return fn();
            queue[index](() => step(index + 1));
        }
        step(0);
    }
}

五、站在巨人肩膀上看世界 🌍

5.1 与History路由的对比

特性 Hash路由 History路由
URL美观度 有#号 干净清爽
兼容性 IE8+ IE10+
服务端支持 无需特殊配置 需要服务端配合
SEO友好度 较差 较好
实现难度 简单 较复杂

5.2 真实框架源码赏析(Vue Router节选)

javascript 复制代码
// Vue Router的hash模式实现
setupListeners() {
    const eventType = supportsPushState ? 'popstate' : 'hashchange'
    window.addEventListener(
        eventType,
        handleRoutingEvent
    )
}

六、写在最后:从面试题到源码大佬的蜕变 🦋

通过这次手写Hash路由的旅程,我们不仅搞懂了:

  • 路由的基本工作原理 🕹️
  • 事件监听的正确姿势 🎧
  • 动态路由的魔法实现 ✨
  • 路由守卫的拦截艺术 🛡️

更重要的是掌握了通过源码学习框架的终极奥义。下次面试官再让你手写路由时,你可以微微一笑:"要不咱们聊聊Vue Router的导航守卫实现?" 😎

相关推荐
汪子熙几秒前
使用 Trae 快速开发能生成二维码的 SAP UI5 应用
前端·trae
猪猪小铁拳3 分钟前
dva调试
前端
路上^_^15 分钟前
CSS核心笔记001
前端·css·笔记
啊吧啊吧曾小白27 分钟前
作用域、闭包与this指向问题
前端·javascript·面试
Linhieng29 分钟前
浏览器扩展与网页交流
前端
小宁爱Python29 分钟前
CSS的复合选择器
前端·css
今天真是星期八31 分钟前
AI 时代如何正确选择前端框架:React、Angular 还是 Vue?
前端
yaoganjili34 分钟前
WebGL打开 3D 世界的大门(六):透视投影
前端·数据可视化
HiF35 分钟前
Hexo博客集成LivePhoto
javascript
ChasLui37 分钟前
[译]在公共领域构建一个速度极快的缓冲数据网格。
前端·neo