前端路由扫盲篇:Hash 模式和 History 模式到底怎么选?

如果把单页应用(SPA)比作一座功能齐备的大别墅,那么前端路由就是这座别墅里的"导览员"。当你在地址栏输入 URL 时,导览员就会根据地址,精准地把对应的页面组件搬到你的眼前。在这个分发过程中,主要有两位"导览员"可供选择:老成持重的 Hash 模式和现代时髦的 History 模式。很多初学者对它们的概念一知半解,面试时被问到区别也往往卡壳。今天,我们就来一场前端路由的扫盲,看看这两大模式各自的底牌是什么,在实际开发中又该如何做出抉择。

什么是路由

路由,本质上就是描述服务器上资源路径的一串地址。当你在浏览器里敲下一个 URL,后端会根据这个路径找到对应的资源,然后返回给你。

但到了前端,事情变得有点不一样。

前端路由:让 URL 和组件建立映射

现在的主流架构是 SPA(单页应用) ------整个应用只有一个 HTML 页面,切换"页面"时不再向服务端发起整页请求,而是由 JavaScript 动态替换当前页面的内容。

这时候问题就来了:页面没刷新,但用户看到的却是不同的"页面",那 URL 怎么办?

前端路由要解决的核心矛盾就是:

页面不刷新,但 URL 要变,而且浏览器前进后退要正常工作。

所以前端路由的本质,就是构建浏览器 URL 地址和组件之间的映射关系------URL 变了,渲染对应的组件,页面本身不刷新。

怎么实现"改 URL 但不刷新页面"

浏览器给了我们两条路。

一、Hash 模式

在浏览器眼里,URL 中 # 后面的部分叫做 hash (哈希值 / 片段标识符)。关键点在于:hash 的变更不会触发页面刷新,这是浏览器天生的行为。

例子:http://127.0.0.1:5500/hash.html#/home

这个链接中的 #/home 就是hsah值。

知道了这些内容那整个流程就清晰了:

  1. 监听 hashchange 事件
  2. 当url变更,hashchange 事件就会触发,通过location.hash获取当前hash值
  3. 拿着这个 hash 值去事先定义好的映射表里查找对应的组件,渲染出来。
javascript 复制代码
// 定义路由映射表
const routes = [
            {
                path: '/home',
                component: () => {
                    return '<h2>首页页面</h2>'
                }
            },
            {
                path: '/hot',
                component: () => {
                    return '<h3>hot page</h3>'
                }
            }
        ]
        
// 监听 hash 变化
window.addEventListener('hashchange', () => {
// 在routes中找到对应的path,并渲染对应的组件
    rederView(location.hash)
})
function rederView (hashVal){
    for(let i =0;i<routes.length;i++){
        if('#'+routes[i].path == hashVal){
            document.getElementById('root').innerHTML = routes[i].component()
           }
      }
}
        

优点:兼容性好,实现简单,不需要服务端配合。

缺点:URL 里永远带着一个 #,不够优雅。

二、History 模式

HTML5 给 window.history 对象新增了几个 API,让前端有能力直接操控浏览器历史记录,而不触发页面刷新:

scss 复制代码
pushState() 向浏览器的历史记录栈中添加一条记录
popState() 从浏览器的历史记录栈中出栈一条记录
replaceState() 替换浏览器的历史记录栈中的栈顶记录

pushState 和 replaceState 都能直接修改浏览器地址栏的 URL,并且不会导致页面刷新------这正是我们需要的。

那前进后退怎么办?浏览器在用户点击前进或后退按钮时会触发 popstate 事件,我们只需要监听它,就能感知用户的历史导航行为,然后渲染对应组件。

javascript 复制代码
        const routes = [
            {
                path: '/home',
                component: () => {
                    return '<h2>history 首页页面</h2>'
                }
            },
            {
                path: '/hot',
                component: () => {
                    return '<h3>history hot page</h3>'
                }
            }
        ]

        window.addEventListener('DOMContentLoaded', () => {
            // 默认展示
            onLoad()
        })

        window.addEventListener('popstate',()=>{   // 监听浏览器的前进后退事件
            renderView(location.pathname)
        })

        function onLoad() {  // 路径变更渲染对应组件
            let linkList = document.querySelectorAll('a[href]')
            // console.log(linkList);
            linkList.forEach(el => {
                el.addEventListener('click', (e) => {
                    e.preventDefault()   // 阻止默认行为

                    history.pushState(null, '', el.getAttribute('href'))  // 进入浏览器的缓存栈

                    renderView(location.pathname)
                })
            })

        }

        function renderView(pathname) {
            routes.forEach((item) => {
                if (pathname == item.path) {
                    document.getElementById('root').innerHTML = item.component()
                }
            })
        }

优点:URL 干净,没有 #,和传统多页应用的 URL 完全一致。

缺点:需要服务端配合------把所有路径都 fallback 到 index.html,否则用户直接访问或刷新深层路径会 404

总结

Hash 模式简单粗暴,靠的是浏览器的"历史遗留特性";History 模式优雅现代,靠的是 HTML5 新增的 API。理解了这两套机制,你就掌握了前端路由的底层原理------不管是 Vue Router 还是 React Router,本质上都是在这两个模式之上做了一层封装和增强。

相关推荐
沙漠之主12 小时前
C++编程教学设计资料:从入门到实战的完整课程方案
java·前端·c++
hasty12 小时前
不上传新包,也能改变用户拿到的版本:npm dist-tag 的 OIDC 权限治理
前端·npm·node.js
Csvn12 小时前
diff 算法(虚拟 DOM Reconciliation)
前端
前端snow13 小时前
ai agent --- 文件存储
前端
Frag0ut14 小时前
Chrome四大版本获取及共存指南:Stable/Beta/Dev/Canary
前端·chrome·浏览器·dev·beta·canary·共存版
IT_陈寒15 小时前
SpringBoot自动配置坑了我一把,原来是这样绕过去的
前端·人工智能·后端
广州华水科技15 小时前
单北斗GNSS变形监测在大坝安全监测中的应用与优势
前端
zeng不错15 小时前
B站 173 个投稿活动看到眼瞎?我写了个扩展,主打一个精准打击
前端
Latchh15 小时前
前端导出的JPEG红字发糊,质量要拉到100才清楚
前端·图像处理·人工智能·计算机视觉
默_笙16 小时前
🚦 请三个 AI 考官给 RAG 打分:量化评估实战(下)
前端·javascript