:::info 前端路由的演化顺序与阶段:

  • 后端路由阶段
  • 前后端分离阶段(ajax阶段)
  • 单页应用程序-SPA

前端路由模式:

  • hash模式
  • history模式

前端路由的底层原理:

  • 通过改变url,但是页面不进行刷新(a标签不行、使用a标签页面会自动刷新)。
    • 通过url路径上的hash值来改变url,页面不会进行刷新操作(底层原理是监听浏览器的hashchange事件)。
    • 通过html5中的history模式修改url,页面也不会进行刷新。
  • 原理:监听路径url的改变,并且在路径改变之后切换到不同的页面。在进行页面切换的时候、请求不同的数据。从而达到不刷新页面的情况下,更新界面。 :::

1 hash路由模式的使用

  1. // hash路由模式的使用
  2. <body>
  3. <div class="app">
  4. <a href="#/home">首页</a>
  5. <a href="#/about">关于</a>
  6. </div>
  7. <div class="router-view"></div>
  8. <script>
  9. // 获取dom元素
  10. const content = document.getElementsByClassName("router-view")[0];
  11. // 监听事件
  12. window.addEventListener('hashchange', () => {
  13. // 根据不同的路径 进行内容也的更换
  14. switch (location.hash) {
  15. case "#/home":
  16. content.innerHTML = "首页";
  17. break;
  18. case "#/about":
  19. content.innerHTML = "关于";
  20. break;
  21. default:
  22. content.innerHTML = ""
  23. }
  24. })
  25. </script>
  26. </body>
  27. // 使用hash模式的时候 本质上就是使用浏览器来监听hashchange事件 第三方库的本质就是hashchange事件的改变,不同的路径更换不同的内容,在我们的单页面开发中,我们就是不同组件之间的相互切换。这就是路由切换的底层原理。

2 history路由模式的使用

:::info 使用的html5的history模式 history接口是html5新增的 它有6种模式在改变url的情况下而不刷新页面。

  • replaceState() 替换原来的路径
  • pushState() 前进,当前的路径向前
  • popState() 后退,当前的路径向后退
  • go() 随意切换路径 传入相应的参数 向前或者向后改变路径 例如go(-1)、go(2)
  • forward() 路径向前 向前改变路径
  • back() 路径后退 向后改变路径 :::

    1. // history路由模式的演示
    2. <body>
    3. <div class="app">
    4. <a href="/home">首页</a>
    5. <a href="/about">关于</a>
    6. </div>
    7. <div class="router-view"></div>
    8. <script>
    9. const aElements = document.getElementsByTagName("a");
    10. const routerViewElement = document.getElementsByClassName("router-view")[0];
    11. // 对数据进行循环遍历
    12. for(let item of aElements) {
    13. item.addEventListener('click', (e) => {
    14. // 阻止a标签的默认事件
    15. e.preventDefault();
    16. const href = item.getAttribute("href");
    17. // 进行路由的切换
    18. history.pushState({}, "", href);
    19. // 调用函数
    20. urlChange();
    21. })
    22. }
    23. // 浏览器的前进与后退执行的popstate的操作 我们可以监听这个函数的改变
    24. window.addEventListener('popstate', urlChange);
    25. // 定义url的改变
    26. function urlChange() {
    27. switch(location.pathname) {
    28. case "/home":
    29. routerViewElement.innerHTML = "首页";
    30. break;
    31. case "/about":
    32. routerViewElement.innerHTML = "关于";
    33. break;
    34. default:
    35. routerViewElement = "";
    36. }
    37. }
    38. </script>
    39. </body>

    3 react-router的基本介绍

    :::info 注意事项:
    从React router4开始 路由不再集中在一个包中进行管理了。

  • react-router是router的核心部分代码

  • react-router-dom是用于浏览器的
  • react-router-native是用于原声运用的

目前使用最新的React Router版本是V5的版本 实际上v4的版本与v5的版本差异并不大

react-router的基本原理:

  • 路由的模式 HashRouter或者BrowserRouter包含了对路由路径改变的监听 并且会将相应的路径传递给子组件。
    • hash模式
      • 使用HashRouter组件对要整个应用程序进行包裹。
      • 将HashRouter映射为组件的形式。
    • history模式
      • 使用BrowserRouter组件对整个应用程序包裹。
      • 直接将BrowserRouter映射为组件标签的形式。
  • 导航的标签 Link组件标签与NavLink组件标签
    • 通常路径的跳转是使用Link组件,在Link组件的的to属性上写上需要跳转的路径。最终会渲染成为a标签。
    • NavLink标签是在Link标签的基础上增加了一些样式属性。
    • to属性是Link组件中最重要的属性,用于设置跳转的路径。
  • Route 组件具体的切换,相当于使用的是组件的占位符
    • Route组件—用于路径的匹配。
    • path属性—用于设置匹配到的路径。
    • component属性—设置匹配到路径后,渲染的组件。
    • exact—精准匹配,只有精准匹配到完全一致的路径,才会渲染对应的组件。 :::
      1. // 安装react-router
      2. // 安装react-router-dom会自动帮助我们安装react-router的依赖。
      3. yanr add react-router-dom
      4. // react-router-dom包的内部会需要依赖react-router包,所有我们不需要单独的安装react-router包。原因是更加方便的管理,我们所有路由中需要使用的组件或者api可以统一从react-router-dom进行到处,统一管理,更加方便。

      4 react-router-dom的基本使用

      ```javascript // 引入路由相关的组件 HashRouter // import { HashRouter, Link, Route } from “react-router-dom”;

// 使用history模式 import { BrowserRouter, Link, Route } from “react-router-dom”;

import Home from “./views/Home”; import About from “./views/About”; import Profile from “./views/Profile”;

function App() { return (

{/ 路由切换区域 /} 首页 关于 我的

  1. {/* 路由展示区域 */}
  2. <Route exact path='/' component={Home}/>
  3. <Route path="/about" component={About}></Route>
  4. <Route path='/profile' component={Profile}/>
  5. </BrowserRouter>
  6. </div>

); }

export default App;

  1. <a name="eWEtW"></a>
  2. # 5 Link组件、NavLink组件的使用
  3. :::info
  4. 从react-router-dom中引入Link组件、NavLink组件<br />import { Nav, NavLink } from "react-router-dom";<br />导航组件的本质就是封装的a标签,同时阻止a标签的模式事件,与用户进行交互、实现不刷新页面的情况下,实现路由更新、组件更新、洁面更新。<br />NavLink组件标签的特点:
  5. - activeStyle--在组件激活时展示的样式,需要设置在每一个组件标签上,可以设置选中时的样式。
  6. - activeClassName--活跃时添加的class样式。
  7. - exact--是否精准匹配路径。
  8. 总结:NavLink标签组件比Link组件更加灵活、可使用组件预留的样式或者相应的类名,还可以进行自定义类名,使用起来是非常方便的。
  9. :::
  10. ```javascript
  11. // 导航标签Link的使用
  12. import { Link, NavLink } from "react-router-dom";
  13. // Link使用详情
  14. <Link exact to="/" activeStrle={{ color: "red" }}>首页<Link>
  15. <Link to="/about" activeStrle={{ color: "red" }}>关于<Link>
  16. <Link to="/profile" activeStrle={{ color: "red" }}>我的<Link>
  17. // NavLink的详细使用
  18. <NavLink to="/" activeClassName="link-active">首页<NavLink>
  19. <NavLink to="/about" activeClassName="link-active">关于<NavLink>
  20. <NavLink to="/profile" activeClassName="link-active">我的<NavLink>

6 Switch组件的使用

  1. // 路由区域正常的使用
  2. import { Route } from "react-router-dom";
  3. <Route to="/" component={组件A}>首页<Route>
  4. <Route to="/about" component={组件B}>关于<Route>
  5. <Route to="/profile" component={组件C}>我的<Route>
  6. // 这里使用动态路由
  7. <Route to="/:id" component={组件D}>用户<Route>
  8. // 未匹配到对应的路由 在实际的业务开发中 一般对应404页面
  9. <Route component={组件E}>
  10. // 上述的Router标签就是一个占位符的形式,当浏览器中路径与to属性的路径进行匹配时。就会展示对应的组件,但是存在一个问题。浏览器中的路径与to属性的路径是模糊匹配的关系,可能存在一个路径对应多个组件的关系 这是我们需要使用exact 这个内置属性了。还需要在外层添加Switch组件进行切换。
  11. // 在实际的开发中,Switch组件利用的是一种排他的思想,从上向下匹配组件,当匹配到第一个组件后,就不会再匹配其他的组件了。我们Switch组件将所有的Route包裹即可。
  12. // Switch组件的使用
  13. <Switch>
  14. <Route exact to="/" component={...}>首页<Route>
  15. <Route to="/about" component={...}>关于<Route>
  16. <Route to="/profile" component={...}>我的<Route>
  17. <Route to="/:id" component={...}>用户<Route>
  18. <Route component={...}>
  19. <Switch>

7 Redirect组件

:::info Redirect用于路由的重定向。当使用这个Redirect组件的时候,就会执行跳转到to属性对应的路径中去。 :::

  1. // 案例演示 根据组件内部的状态进行鉴权 是否有权限查看某个页面。
  2. class Demo extends React.PureComponent {
  3. constructor(props) {
  4. super(props)
  5. this.state = {
  6. isLogin: true
  7. }
  8. }
  9. render() {
  10. return (
  11. {
  12. this.state.isLogin ? "欢迎回来" :<Redirect to="/login" />
  13. }
  14. )
  15. }
  16. }

8 嵌套路由使用

:::info 嵌套路由在日常的开发中使用是非常常见的。其实原理很简单就是在需要使用路由的地方写好路由表,在父组件中写好路由表,然后引入子组件,子组件Router的to属性会与浏览器的url进行路径的匹配,当路径匹配正确后,就会展示相应的字组件,这就是嵌套路由的实现。 :::

9 手动跳转路由

:::info 手动跳转路由有两种方式:通过javascript来进行路由跳转的前提,必须要获取history对象。

  • 如果组件是通过路由跳转过来的,也就是说在组件的外部包裹了一层Router组件,那么它将会默认将路由的history、location等属性传递过来。我们在组件的props属性中可以直接获取,可以直接使用this.props.history.push(“/home”)等方式来进行路由的跳转。
  • 如果改组件是一个普通渲染的组件,是无法获取history、location、match对象的。
    • 如果希望我们的普通App组件获取history属性的话,需要满足下面这个条件
      • App组件必须包裹在router组件之内。
      • App组件使用WithRouter高阶组件进行包裹。 ::: ```javascript // 使用路由组件对整个应用程序进行包裹 import { HashRouter } from “react-router-dom”;

// index.js 整个应用程序的根组件 import React from ‘react’; import ReactDOM from ‘react-dom’; import App from ‘./App’;

ReactDOM.render( // 对整个应用程序的根组件 使用路由组件进行包裹 , document.getElementById(‘root’) );

// App根组件中的渲染函数 function App(props) { // 在这里就可以获取到路由的相关属性了 const history = props.history; console.log(history);

handleJump() { // 利用history即可 传入相对应的路径 history.push(“/login”) }

  1. retrun (
  2. <div>
  3. 我是App组件
  4. <button onClick={() => this.handleJump() }>手动跳转路由</button>
  5. </div>

) }

// 使用WithRouter高阶组件进行包裹 export default WithRouter(App);

  1. <a name="u4oVZ"></a>
  2. # 10 动态路由的使用
  3. :::info
  4. 动态路由指的是路由的路径中某一部分的内容是固定的,其中还有一部分的值是动态,前端对路径进行解析的时候,可以根据动态参数的不同发送不同的网络请求,获取不同的数据,达到动态展示的效果,这就是动态路由。动态路由可以携带相应的参数。
  5. :::
  6. <a name="xjC7b"></a>
  7. # 11 参数的传递
  8. :::info
  9. react-router中参数的传递有三种方式:
  10. - 使用动态路由来传递参数。
  11. - 使用search来传递参数-在路径的后面跟上需要搜索的search参数。
  12. - 使用to属性的时候、to属性可以传递一个对象,将需要传递的参数放置于对象中。
  13. :::
  14. ```javascript
  15. // 1. 使用动态路由的形式传递参数
  16. 在路由的路径中,/detail路径对应的是Detail详情组件。我们将Route中的路径写为"/detail/:id"。那么路径"/detail/abc"或者"/detail/123"都将匹配到该route,并且进行显示。
  17. 这种匹配规则,我们称之为动态路由。通常情况下我们使用动态路由可以通过路由传递参数。
  18. // 动态路由的使用
  19. import { NavLink } from "react-router-dom";
  20. <NavLink to="/detail/abc123">商品详情<NavLink>
  21. // 在业务组件使用props.match来获取传递的参数
  22. // 2. 使用search路径查询部分传递参数
  23. import { NavLink } from "react-router-dom";
  24. <NavLink to="/detail?name=coderweiwei&age=18">详情2<NavLink>
  25. 在业务组件中使用props.location在location中获取传递的参数 参数在search属性上面
  26. // 3. 使用Link或者NavLink组件的to属性可传递一个对象,将需要传递的参数放置于对象中。
  27. import { NavLink } from "react-router-dom";
  28. <NavLink to={{
  29. pathname: "/detail", // 需要导航的路径
  30. search: "?name=coder&age=123" // 查询的参数键值对
  31. hash: "document", // hash值 一般使用hashRouter时会使用
  32. state: { height: 190, weight: 120 }, // 传递的任意参数都是可以放入到state
  33. }}>查看详情
  34. </NavLink>
  35. // 在业务组件中使用props.location在location中获取传递的参数 所有的属性都在location对象中
  36. // 上述各种传参的形式 在对应的业务组件中都是可以获取到的 一般在props属性中。