前端路由

0 阅读5分钟

它的核心思想是:一切皆资源,但资源的获取和切换,由前端 JavaScript 来控制,不再依赖后端服务器的实时响应。

具体来说,前端路由利用浏览器提供的特性,在不刷新页面的前提下,去改变浏览器地址栏的 URL ,并根据 URL 的变化,动态地去渲染对应的页面组件。

react-router-dom 是 React 官方推荐的 Web 应用路由库
渲染规则: 除了导航组件(Link/NavLink)会渲染外,只有匹配当前 URL 的 Route element 才会渲染。

组件类别核心组件主要作用
路由器 (Routers)BrowserRouterHashRouter相当于整个应用的"地基",提供路由环境。 负责: 1. 监听 URL 的变化(无论是 # 还是 History API) 2.把当前 URL 信息存储到 React 的上下文中,让子组件都能访问到
路由匹配器 (Matchers)RoutesRouteSwitch根据当前 URL,决定"显示哪个组件"。
导航组件 (Navigation)LinkNavLinkNavigate提供让用户"触发路由跳转"的方式。

路由

在 React 应用中,我们通常使用 react-router-dom 这个库来实现前端路由。它提供了两种路由模式:

  • HashRouter:

    这种模式利用 URL 中的 #(锚点)符号。例如:http://example.com/#/home# 及其后面的部分被称为 hash

    改变 hash 值,浏览器并不会向服务器发送请求,也就不会刷新页面。同时,浏览器提供了 hashchange 事件,我们可以监听这个事件,当 hash 改变时,获取最新的 hash 值,然后渲染对应的页面组件。

  • BrowserRouter:

    三种方法

    1. pushState(state, title, url)
    • 操作对象:浏览器历史记录栈

    • 行为:在栈顶添加一条新记录

    • URL 变化:地址栏立即变为新 URL

    • 页面刷新:否

    • 触发 popstate:否

    • 使用场景:用户主动触发导航(如点击链接、表单提交后的跳转)

      2.replaceState(state, title, url)

    • 操作对象:浏览器历史记录栈

    • 行为:用新记录替换栈顶的当前记录

    • URL 变化:地址栏立即变为新 URL

    • 页面刷新:否

    • 触发 popstate:否

    • 使用场景:不希望用户后退到当前页面的场景(如登录成功后替换登录页)

      3.popState 事件
    • 本质:浏览器原生事件

    • 触发时机:历史记录条目发生变化时(用户点击前进/后退按钮,或调用 back()
      forward()go() 方法)

    • 不触发时机:调用 pushState() 或 replaceState() 时

    • 作用:作为监听器,通知 JavaScript 环境"当前激活的历史记录已改变"

    • 数据获取:通过 event.state 读取与该记录关联的状态对象

路由匹配器

  • Routes:遍历子 Route,只渲染第一个匹配的组件(独占匹配)

  • Route:定义路由规则,path 是匹配条件,element 是要渲染的组件

<Routes>
  <Route path="/users" element={<UserList />} />
  <Route path="/users/:id" element={<UserDetail />} />
</Routes>

翻译:当url为path的时候,将页面渲染为element的组件
如果 URL 是 /users/123

  • 第一个 path="/users" 不匹配(因为多了 /123

  • 第二个 path="/users/:id" 匹配 ✅

  • 只渲染 UserDetail

导航组件

  • <Link> 基础导航组件,点击后跳转到指定路径,渲染为 <a> 标签。

  • <NavLink> 是 <Link> 的增强版,能根据当前 URL 自动匹配并添加高亮样式(active 类),适合导航菜单。

  • <Navigate> 不是点击触发的链接,而是渲染即跳转,用于条件性重定向(如登录状态判断后自动跳转)。

    <Link to="/about">关于我们</Link>
    
    <NavLink to="/" className={({ isActive }) => isActive ? 'active-link' : ''}>
      首页
    </NavLink>
    <NavLink to="/about" className={({ isActive }) => isActive ? 'active-link' : ''}>
      关于
    </NavLink>
    <NavLink to="/contact" className={({ isActive }) => isActive ? 'active-link' : ''}>
      联系
    </NavLink>
    
     .active-link {
        color: red;          /* 激活时文字变红 */
        font-weight: bold;   /* 激活时加粗 */
        border-bottom: 2px solid red;  /* 激活时加下划线 */
    }
    

你在 /about 页面:"关于"按钮自动变红加粗(因为匹配)
你在 /contact 页面:"联系"按钮自动变红加粗
你在 / 页面:"首页"按钮自动变红加粗

  {isLoggedIn ? <Dashboard /> : <Navigate to="/login" />}//进行登录状态的判断

<Navigate>
基本用法

   import { Navigate } from 'react-router-dom'
   <Navigate to="/home" replace />

核心属性:

to 必填。表示目标路径,如 "/home" 或 { pathname: "/home" }
replace 非必填。表示是否替换历史记录,默认 false
state 非必填。表示传递状态数据到目标页面

动态路由

动态路由就是在路由路径中使用占位符(参数) ,让一个路由规则能匹配一类 URL,而不是一个固定的 URL

一般语法:

   <Route path="/user/:id" element={<UserProfile />} />
   //   :id 是占位符,匹配 /user/ 后面的任意值
   //   一个路由规则可以匹配无数个不同的 URL

在 React Router 中,只要路径中以冒号 : 开头的部分,都是占位符(动态参数)

获取参数:
useParams 是 React Router 提供的钩子函数,用于获取动态路由中的参数。
基本用法:

  import { useParams } from 'react-router-dom'

 function UserProfile() {
    const { id } = useParams()
    return <div>用户ID:{id}</div>
 }

路由配置:

  <Route path="/user/:id" element={<UserProfile />} />

嵌套路由

嵌套路由就是在父组件中定义子路由,实现布局共享。比如,用户中心有侧边栏,点击不同选项只切换右侧内容,侧边栏保持不变。

核心组件:Outlet
<Outlet /> 是子路由的占位符,父组件中放它,子组件就会渲染在这里。

import { Outlet } from 'react-router-dom'

function UserLayout() {
return (
 <div>
   <h1>用户中心</h1>
   <nav>
     <Link to="/user/profile">个人资料</Link>
     <Link to="/user/settings">设置</Link>
   </nav>
   <Outlet />  {/* 子路由渲染在这里 */}
 </div>
)
}

// 路由配置
<Routes>
<Route path="/user" element={<UserLayout />}>
 <Route path="profile" element={<Profile />} />
 <Route path="settings" element={<Settings />} />
</Route>
</Routes>

在嵌套路由中,匹配多个 Route 是它的核心设计

/user/profile 这个 URL 包含了两层信息

  1. 第一层 /user:告诉我们"这是用户中心页面"(需要渲染 UserLayout 这个框架)。
  2. 第二层 /profile:告诉我们"当前在用户中心的个人资料页"(需要把 Profile 这个具体内容,渲染到框架的 Outlet 里)。

路由重定向

路由重定向就是当用户访问一个旧地址时,自动将其跳转到新地址。比如页面搬家,网站改版或者登录拦截等等。

两种重定向方式
1:<Navigate> 组件(声明式)

 import { Navigate } from 'react-router-dom'

 function App() {
    return (
      <Routes>
        {/* 访问 /about 时自动跳转到 /company */}
           <Route path="/about" element={<Navigate to="/company" replace />} />
           <Route path="/company" element={<Company />} />
     </Routes>
)
}

2:useNavigate 钩子(编程式)

   import { useNavigate } from 'react-router-dom'

   function LoginPage() {
     const navigate = useNavigate()
  
     const handleLogin = () => {
       // 登录成功后跳转到首页
      navigate('/')
    }
   }

404处理(必写!)

用户可能输入任何 URL,你无法控制。如果不写 404,用户访问不存在的页面时,会看到一片空白,体验极差。

import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';

const NotFound = () => {
  let navigate = useNavigate();

  useEffect(() => {
    // 一个简单的定时器,3秒后跳转回首页
    const timer = setTimeout(() => {
      navigate('/');
    }, 3000);
    
    // 在组件卸载时清理定时器,是一个好的实践
    return () => clearTimeout(timer);
  }, [navigate]); // 依赖项中加入 navigate

  return (
    <>
      <h1>404 - 页面未找到</h1>
      <p>3秒后将自动返回首页</p>
    </>
  );
};

export default NotFound;