手撕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的导航守卫实现?" 😎

相关推荐
刺客_Andy几秒前
React 第三十五节 Router 中useNavigate 的作用及用途详解
前端·react.js
哄哄5751 分钟前
微信小程序键盘弹起时,底部输入框抬起至键盘上方,顶部导航栏固定不动
前端
南囝coding3 分钟前
这款AI自动生成播客工具,必须收藏!
前端·后端
Mapmost3 分钟前
【AI技术闲谈】AI一键生成前端代码?实测4款工具后的操作指南
前端·ai编程
用户0595661192098 分钟前
校招 java 基础面试题目及解析
java·面试
37手游后端团队40 分钟前
8分钟带你看懂什么是MCP
人工智能·后端·面试
玲小珑43 分钟前
Auto.js 入门指南(六)多线程与异步操作
android·前端
白瓷梅子汤1 小时前
跟着官方示例学习 @tanStack-table --- Header Groups
前端·react.js
喝牛奶的小蜜蜂1 小时前
个人小程序:不懂后台,如何做数据交互
前端·微信小程序·小程序·云开发
FG.1 小时前
Day13
java·面试