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

相关推荐
Pedantic1 小时前
SwiftUI 手势层级(Gesture Hierarchy)详解
前端
飘尘1 小时前
前端转型全栈(Java后端)的快速上手指引
前端·后端·全栈
一颗烂土豆1 小时前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
浏览器工程师2 小时前
AI Agent 接浏览器任务,先别让它一路点到底
前端·后端
雨季mo浅忆2 小时前
VSCode自动格式化三要素
前端
爱勇宝3 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员
kyriewen4 小时前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
user20585561518136 小时前
Windows 项目安装时报 `node-sass` 错误,如何快速处理
前端
LiaCode6 小时前
Redis 在生产项目的使用
前端·后端