# 🌐 前端路由完全指南:从原生实现到React Router实战,构建现代化单页应用

114 阅读7分钟

前端路由:单页应用的导航系统

在前端框架(Vue/React/Angular)中,路由是一个核心概念,它负责根据URL的变化,在同一个页面内动态切换显示不同内容。可以把它理解为浏览器内的导航系统——就像手机App中的页面切换,而不是传统的多页面网站跳转。

一、理解前端路由

1.1 什么是前端路由?

前端路由是现代单页应用(SPA)的核心机制,它通过监听和操作浏览器地址(URL)的变化,在同一个HTML文档内动态地切换显示不同的视图或组件,而无需向服务器请求新的页面。

1.2 为什么需要前端路由?

传统网站中,每个页面都是独立的HTML文件,点击链接会:

  1. 向服务器发送请求
  2. 服务器返回新的HTML
  3. 浏览器刷新整个页面

而在现代单页应用(SPA)中:

  • 整个应用只有一个HTML文件
  • 页面切换时不刷新浏览器
  • 所有内容动态加载和更新
  • 用户体验更流畅(类似原生App)

1.3 传统网站 vs 单页应用(SPA)

传统网站是多页应用(MPA),每次导航都伴随完整的页面刷新。SPA则将所有内容集成在一个页面中,通过前端路由实现局部内容的无刷新切换,极大地提升了应用的响应速度和交互体验。

二、两种路由模式

2.1 Hash模式

Hash路由利用URL中#号(锚点)后面的部分(即hash)来模拟路径的变化。浏览器不会将#后面的内容发送到服务器,因此完全在客户端实现。

原生JS实现示例

用传统js实现一个简单的路由,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
    /* 样式部分省略 */
    </style>
</head>
<body>
    <div id="app">前端路由js实现</div>
    <div>
        <a href="#/home">Home</a>
        <a href="#/about">about</a>
        <a href="#/about1">about1</a>
    </div>
    <script>
        const router = {//创建路由对象
            '/home':'<h2>首页</h2><p>欢迎来到首页</p> ',
            '/about':'<h2>关于页</h2><p>欢迎来到关于页</p> ',
            '/about1':'<h2>联系页</h2><p>欢迎来到联系页</p> '
        }

        //获取路由路径函数
        const getPath = function(){
            return window.location.hash.slice(1)||'/home'
        }
        
        //挂载显示页面函数
        const showPages = function(path){
            const app = document.getElementById('app')
            if(router[path]){
                app.innerHTML=router[path]
            }else{
                app.innerHTML='<h2>没有此页面</h2>'
            }
        }
        
        //更新函数
        const upData = function(){
            const path =getPath();
            console.log(path)
            showPages(path);
        }

        window.addEventListener('hashchange',upData);
        window.addEventListener('load', upData);
        upData()
    </script>
</body>
</html>

屏幕录制 2025-12-21 175807.gif

代码解析
  • 前端路由的核心机制:URL地址只改变了#后面的字符,但没有向服务器发送HTTP请求,所有视图切换都在浏览器本地完成。这是Hash模式前端路由的特点,实现了单页应用的无刷新体验。
  • 路由路径的获取window.location.hash.slice(1) || '/home'
    • window.location.hash 获取URL中#号及其后面的内容(例如:#/about
    • .slice(1) 移除开头的#号,得到路由路径(例如:/about
    • || '/home' 默认值处理:如果#后面没有内容(空值),则返回默认路径/home
  • DOM操作的核心const app = document.getElementById('app')
    • 通过id获取页面上的DOM元素作为视图容器
    • 所有路由对应的内容都将动态渲染到这个容器中
  • 动态内容更新app.innerHTML = router[path]
    • 根据当前路径从router对象中查找对应的HTML内容
    • 将找到的内容设置为容器的内部HTML,实现页面内容的动态替换
  • 事件监听机制window.addEventListener('hashchange', updatePage)
    • 实时监听URL中#号后面部分的变化
    • 每当hash值改变时,自动触发updatePage函数更新页面
    • 这是实现无刷新页面切换的关键技术

2.2 History模式

History路由利用HTML5的History API(pushState, replaceState)来操作浏览器的会话历史栈,可以创建出没有#号的干净URL(如 example.com/home)。但它的实现需要服务器端的配合,以防止直接访问或刷新子路由时返回404错误。

2.3 Hash vs History对比表

对比维度Hash路由History路由重点说明
URL格式example.com/#/home
❌ 带#号不美观
example.com/home
✅ 干净标准
最直观区别
服务器配置不需要特殊配置必须配置SPA重定向部署关键差异
兼容性IE6+ 全支持IE10+ 现代浏览器旧项目注意兼容性
SEO支持很差良好对公网站点很重要
实现原理location.hash + hashchange事件history.pushState + popstate事件API不同
锚点功能冲突无法使用正常使用Hash被路由占用
部署平台✅ GitHub Pages等静态托管❌ 需SPA支持的服务免费托管平台友好
刷新问题✅ 刷新正常显示❌ 刷新可能404History需服务器配合
学习成本简单中等新手建议从Hash开始
适用场景内部系统、Demo、
兼容旧浏览器项目
公网应用、电商、
对SEO/URL有要求
根据需求选择

🎯 一句话选择建议

  • 用Hash路由:需要简单快速、兼容旧浏览器、无法改服务器配置
  • 用History路由:需要专业美观、SEO重要、能控制服务器

三、React Router实战

3.1 环境搭建

创建Vite+React项目

那么在现代技术栈,我们怎么实现SPA(单页面应用),使用react+vite框架,带你们从头写一个spa页面。

部署vite,这里就不过多阐述了,不熟悉的小伙伴可以去看这篇文章(Vite:现代前端构建工具的革命与实战指南)juejin.cn/post/758436…

如图:

屏幕截图 2025-12-21 203306.png

步骤与命令详解:

  1. 启动创建命令npm init vite
  2. 输入项目名称react-router-test
  3. 选择框架React
  4. 选择开发语言JavaScript
  5. 选择打包工具(实验性)No
  6. 安装与启动Yes

最终结果: 执行完毕后,Vite会创建项目文件夹,安装依赖并启动开发服务器,通常可通过 http://localhost:5173 访问。

安装react-router-dom

构建好项目后,我们在在当前目录终端下输入npm install react-router-dom命令,安装最新的Web应用路由库:

image.png

安装完成后,在package.json文件下可以看到依赖:"react-router-dom": "^7.11.0"

{
  "name": "react-router-test",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "react-router-dom": "^7.11.0" // 我们安装的依赖
  }
}

image.png

3.2 项目结构

完成后在src目录下新建两个文件夹routerpages,创建对应的文件。

src/
├── router/
│   └── index.jsx    # 路由配置文件
├── pages/
│   ├── Home.jsx     # 首页组件
│   └── About.jsx    # 关于页面组件
└── main.jsx         # 应用入口文件

image.png

3.3 页面组件开发

Home.jsx
import {
    useState, //响应式数据
} from 'react';

const Home = () => {
    const [obj, setobj] = useState({
        name: "杨剑铭",
        age: "18",
        histoy: "睡觉"
    })

    const changeName = () => {
        setobj({
            ...obj,
            name: obj.name === "杨剑铭" ? "杨铭" : "杨剑铭"
        })
    }

    const changeAge = () => {
        setobj({
            ...obj,
            age: obj.age === "18" ? "100" : "18"
        })
    }
    
    const changeHistoy = () => {
        setobj({
            ...obj,
            histoy: obj.histoy === "睡觉" ? "学习" : "睡觉"
        })
    }
    
    return (
        <div>
            <h1>Home</h1>
            <p>{obj.name}</p>
            <p>{obj.age}</p>
            <p>{obj.histoy}</p>
            <button onClick={changeName}>修改名字</button>
            <button onClick={changeAge}>修改年龄</button>
            <button onClick={changeHistoy}>修改动作</button>
        </div>
    )
}
export default Home;
About.jsx
import { useState } from "react"

const About = () => {
    const [count, setcount] = useState(0)
    return (
        <div>
            <h1>About</h1>
            <button onClick={() => setcount(count - 1)}>count--</button>
            <button onClick={() => setcount(count + 1)}>count++</button><br></br>
            <button>{count}</button>
        </div>
    )
}
export default About

3.4 路由配置

router/index.jsx
import {
    Routes, //路由集合
    Route   //路由实例,路由规则
} from 'react-router-dom'
import Home from '../pages/Home.jsx'
import About from '../pages/About.jsx'

export default function AppRoute() {
    return (
        <Routes>
            <Route path='/' element={<Home />} />
            <Route path="/about" element={<About />} />
        </Routes>
    )
}

代码解析: Routes 作为路由容器,包裹所有 Route 规则。每个 Route 定义了一条路径与对应组件的映射关系。

3.5 主应用集成

App.jsx详解
import {
  BrowserRouter as Router, // 取别名,代表BrowserRouter
  Link
} from 'react-router-dom'
import AppRoute from './router/index.jsx'

function App() {
  return (
    <>
      <Router>
        <nav>
          <ul>
            <li>
              <Link to="/about">About</Link><br />
              <Link to="/">Home</Link>
            </li>
          </ul>
        </nav>
        <AppRoute />
      </Router>
    </>
  )
}
export default App

1. 导入部分:

  • BrowserRouter as Router: 使用路由器组件,并提供路由上下文。
  • Link: 导航组件,用于无刷新页面跳转。
  • AppRoute: 自定义的路由配置组件。

2. App 组件结构:

  • <Router>: 顶层容器,必须包裹所有需要使用路由功能的组件。
  • <nav>: 导航区域,使用 Link 组件。
  • <AppRoute />: 路由渲染区域,根据当前URL动态显示对应组件。

3. 完整工作流程:

用户点击 Link → 触发路由跳转 → Router 捕获变化 → AppRoute 根据新 URL 匹配路由 → 渲染对应的页面组件

image.png

3.6 效果展示

屏幕录制 2025-12-21 215728.gif

四、核心要点总结

前端路由的本质

  • 目标:实现单页应用(SPA)的无刷新页面切换
  • 核心:URL变化时,在同一个页面内动态更新内容
  • 对比:传统多页网站每次跳转都刷新整个页面,SPA仅更新部分内容

模式选择指南

  • Hash路由:简单易用,兼容性好,URL带#
  • History路由:URL美观,SEO友好,需服务器配合

一句话总结

前端路由通过监听URL变化动态更新页面内容,实现了单页应用的流畅导航体验,是现代Web应用不可或缺的基础设施。


以上就是全部路由的教程了,望学习愉快。