美文网首页
前端路由原理和React Router

前端路由原理和React Router

作者: forever_提拉米苏 | 来源:发表于2021-06-16 17:24 被阅读0次

前端路由原理

前端三大框架 Angular、React、Vue ,它们的路由解决方案 angular/router、react-router、vue-router 都是基于前端路由原理进行封装实现的,因此将前端路由原理进行了解和掌握是很有必要的。

路由的概念起源于服务端,在以前前后端不分离的时候,由后端来控制路由。但由于后端路由还存在着自己的不足,前端路由才有了发展空间。路由的映射函数通常是进行一些 DOM 的显示和隐藏操作,当访问不同的路径的时候,会显示不同的页面组件。前端路由主要有两种实现方案:Hash和History。

Hash模式

hash模式就是基于 location.hash 来实现的,原理很简单,location.hash 的值就是 URL 中 # 后面的内容。比如https://www.xxxxxx.com#search的 location.hash 的值为 '#search'

hash 有下面几个特性:

  • URL 中 hash 值只是客户端的一种状态,也就是说当向服务器端发出请求时,hash 部分不会被发送。
  • hash 值的改变,都会在浏览器的访问历史中增加一个记录。因此我们能通过浏览器的回退、前进按钮控制hash 的切换。
  • 我们可以使用 hashchange 事件来监听 hash 的变化。

那么如何来触发hash改变(hashchange 事件)呢?

  1. 通过 a 标签,并设置 href 属性,当用户点击这个标签后,URL 就会发生改变,也就会触发 hashchange 事件了:
<a href="#search">search</a>
  1. 直接使用 JavaScript来对 loaction.hash 进行赋值,从而改变 URL,触发 hashchange 事件:
location.hash="#search"

History模式

由于hash模式下使用时都需要加上 #,并不是很美观。到了 HTML5,又提供了 History API 来实现 URL 的变化。其中做最主要的 API 有以下两个:history.pushState()history.repalceState()。这两个 API可以在不进行刷新的情况下,操作浏览器的历史纪录。唯一不同的是,前者是新增一个历史记录,后者是直接替换当前的历史记录。代码格式如下:

window.history.pushState(null, null, path);
window.history.replaceState(null, null, path);

history 有下面几个特性:

  • pushState 和 repalceState 的标题(title):一般浏览器会忽略,最好传入 null ;
  • 我们可以使用 popstate 事件来监听 url 的变化;
  • history.pushState() 或 history.replaceState() 不会触发 popstate 事件,这时我们需要手动触发页面渲染;

在对前端路由原理有了基本的掌握后,就可以尝试去阅读 vue-router 和 react-router 的源码实现。下面来看下react-router。


React Router

React Router 中的组件主要分为三类:

  • 路由组件,例如 BrowserRouter和 HashRouter
  • 路由匹配器,例如 Route 和 Switch
  • 导航,例如 Link,NavLink 和 Redirect

下面逐一展开介绍:

路由组件

路由组件分为两种:BrowserRouter(对应前端路由history 模式) 和 HashRouter(对应前端路由hash 模式),用法一样,只是 url 展示不同,其中 hash 模式带有 # 号符。

BrowserRouter:http://localhost:3000/page2
HashRouter:http://localhost:3000/#/page2

// BrowserRouter:
<BrowserRouter>
    <Route path="/page1" exact component={Page1}></Route>
    <Route path="/page2/:id" exact component={Page2}></Route>
</BrowserRouter>
// HashRouter:
<HashRouter>
    <Route path="/page1" exact component={Page1}></Route>
    <Route path="/page2/:id" exact component={Page2}></Route>
</HashRouter>

路由匹配器

  1. Route
    Route 是用于声明路由映射到应用程序的组件层。
    路由Route的参数介绍如下:
  • path
    string 类型,用来指定路由跳转路径,根据 path 和 url 匹配到对应的页面;如下所示
// 路由配置
<Route path="/page1" exact component={Page1}></Route>
// 页面访问 http://localhost:3000/page1
  • exact
    boolean 类型,用来精确匹配路由,如果为 true 则精确匹配,否则为正常匹配;如下所示
// exact = true 时
<Route path="/page1" exact component={Page1}></Route>
// 浏览器通过 http://localhost:3000/page1/one 访问不到 page1 页面

// exact = fasle 时
<Route path="/page1" exact={false} component={Page1}></Route>
// 浏览器通过 http://localhost:3000/page1/one 可以访问到 page1 页面
  • sensitive
    boolean 类型,用来设置是否区分路由大小写,如果为 true 则区分大小写,否则不区分;如下所示
// sensitive = true 时
<Route path="/page1" sensitive component={Page1}></Route>
// 浏览器通过 http://localhost:3000/PAGE1 访问不到 page1 页面

// sensitive = fasle 时
<Route path="/page1" sensitive={false} component={Page1}></Route>
// 浏览器通过 http://localhost:3000/PAGE1 可以访问到 page1 页面
  • strict
    boolean 类型,对路径末尾斜杠的匹配。如果为 true,path 为 '/page1/' 将不能匹配 '/page1' 但可以匹配 '/page1/one'。;如下所示
// strict = true 时
<Route path="/page1/" strict component={Page1}></Route>
// 浏览器通过以下 url 访问不到 page1 页面
http://localhost:3000/page1
// 浏览器通过以下 url 可以访问到 page1 页面
http://localhost:3000/page1/one

// strict = fasle 时
<Route path="/page1/" strict={false} component={Page1}></Route>
// 浏览器通过以下 url 可以访问到 page1 页面
http://localhost:3000/page1
http://localhost:3000/page1/one
  • component
    设置路由对应渲染的组件,如下所示Page1为要渲染的组件
<Route path="/page1/" exact component={Page1}></Route>
  • render
    通过render函数返回路由对应渲染的组件或者dom,好处是不仅可以通过 render 方法传递 props 属性,并且可以传递自定义属性。如下所示
<Route path='/about' exact render={(props) => {
    return <Page1 {...props} name={'name1'} />
}}></Route>

class Page1 extends React.Component {
  componentDidMount() {
    console.log(this.props) 
    // this.props:
    // history: {length: 9, action: "POP", location: {…}, createHref: ƒ, push: ƒ, …}
    // location: {pathname: "/home", search: "", hash: "", state: undefined, key: "ad7bco"}
    // match: {path: "/home", url: "/home", isExact: true, params: {…}}
    // name: "name1"
  }
}
  1. Switch
    如果路由 Route 外部包裹 Switch 时,路由匹配到对应的组件后,就不会继续渲染其他组件了。但是如果外部不包裹 Switch 时,所有路由组件会先渲染一遍,然后选择所有匹配的路由进行显示。
// 当没有使用 Switch 时
<BrowserRouter>
  <Route path="/page1" component={Page1}></Route>
  <Route path="/" component={Page2}></Route>
  <Route path="/page3/:id" exact component={Page3}></Route>
</BrowserRouter>
// 当面访问 http://localhost:3000/page1 时,浏览器会同时显示 page1 和 page2 页面的内容 

// 当使用 Switch 时
<BrowserRouter>
  <Switch>
    <Route path="/page1" component={Page1}></Route>
    <Route path="/" component={Page2}></Route>
    <Route path="/page3/:id" exact component={Page3}></Route>
  </Switch>
</BrowserRouter>
// 当面访问 http://localhost:3000/page1 时,浏览器只会显示 page1 页面的内容 

导航

  1. Link
    用来指定路由跳转,Link的参数介绍如下:
  • to
    可以通过字符串执行路由跳转,也可以通过对象指定路由跳转,如下所示
// 通过字符串
<Link to='/page2'>
  <span>跳转到 page2</span>
</Link>  

// 通过对象
<Link to={{
    pathname: '/page2',
    search: '?name=name1',
    hash: '#someHash',
    state: { age: 11 }
  }}>
  <span>跳转到 page2</span>
</Link>

通过对象指定路由跳转时,各字段的含义如下:
pathname: 表示跳转的页面路由 path
search: 表示查询参数的字符串形式,即等同于 location 中的 search
hash: 放入网址的 hash,即等同于 location 中的 hash
state: 可以通过这个属性,向新的页面隐式传参,在上面的例子中page2 中可以通过 this.props.location.state 可以拿到 age: 11;

  • replace
    如果设置 replace 为 true 时,表示用新地址替换掉上一次访问的地址;
  1. NavLink
    这是 Link 的特殊版,顾名思义这就是为页面导航准备的,因为导航需要有 “激活状态”。除Link的固定参数外,还有如下可选参数:
  • activeClassName: string,导航选中激活时候应用的样式名
  • activeStyle: object,如果不想使用样式名就直接写 style,
  • exact: bool,若为 true,只有当访问地址严格匹配时激活样式才会应用
  • strict: bool,若为 true,只有当访问地址后缀斜杠严格匹配(有或无)时激活样式才会应用
  • isActive: func,决定导航是否激活,或者在导航激活时候做点别的事情。不管怎样,它不能决定对应页面是否可以渲染。
  1. Redirect
    Redirect用于路由的重定向,它会执行跳转到对应的to路径中,其中参数to的规则同Link一样。
<Redirect to='/' />

withRouter

withRouter 可以将一个非路由组件包裹为路由组件,使这个非路由组件也能访问到当前路由的 match, location, history对象。

class Component1 extends React.Component<any> {
  handleClick () {
    this.props.history.push('/page2');
  }
  render () {
    return <div onClick={() => this.handleClick()}>this is component1</div>;
  }
}

export default withRouter(Component1);

参数传递

传递参数有三种方式:

  1. 动态路由的方式
    假如/detail的路径对应 一个组件Detail,若将路径中的Route匹配时写成/detail/:id,那么/detail/123,/detail/xyz都可以匹配到该Route并进行显示
// 路由配置
<Route path="/detail/:id" exact component={Detail}></Route>
// 路由跳转
this.props.history.push('/detail/1000');
// 参数获取
this.props.match.params;  // {id: "1000"}
  1. search传递参数
    根据参数to的不同书写格式,search传参可以分为两种形式:
<Link to="/detail2?name=boge&age=20">详情2</Link>
<Link to={{ pathname: '/detail2', search: '?name=boge&age=20'}}>详情2</Link>

// 参数获取
this.props.location.state;  // {name:'boge', age:20}
  1. 隐式传参
    所传递的参数不可见
//数据定义
const data = {id:3,name:sam,age:36};
const path = {
    pathname: '/user',
    query: data,
}
this.props.history.push(path);

// 参数获取
this.props.location.query;   // {id:3,name:sam,age:36};

嵌套路由

嵌套路由就是在子页面中再设置一层新的路由导航规则。重点在于不能在父级加 exact(精准匹配),因为先要匹配父级然后才能匹配子集。

// appRouter.js
<BrowserRouter>
    <Route path="/" exact component={Index} />
    <Route path="/video/" component={Video} />
    <Route path="/workplace/" component={Workplace} />
</BrowserRouter>

// video.js
<div className="videoContent">
    <h3>视频教程</h3>
    <Route path="/video/react/" component={React} />
    <Route path="/video/vue/" component={Vue} />
</div>

为什么我能够看得更远,那是因为我站在巨人的肩上,以上内容来源:
深度剖析:前端路由原理
一文搞定 React 路由

相关文章

  • React Router-简单原理

    以下内容主要参考自 深入理解 react-router 路由系统react-router的实现原理前端路由实现与 ...

  • 前端路由原理和React Router

    前端路由原理 前端三大框架 Angular、React、Vue ,它们的路由解决方案 angular/router...

  • react-router

    [react-router]路由原理 参考链接 [react-router]hashHistory和browser...

  • 重点掌握

    【前端性能优化汇总】【Webpack原理+React原理+Redux+React Router】【输入URL后发生...

  • React 刷新404问题

    react-router 因为前端路由更容易确定问题,更方便分析,而且对于react-router更熟悉,所以首先...

  • 四、使用antd搭建简单后台页面

    1、安装react-router-dom实现前端路由,执行:cnpm install --save react-r...

  • React-Router 和 React-Router-dom

    React-Router 和 React-Router-dom 的区别 react-router 提供了路由核心a...

  • 2018-12-21路由

    1.路由 React路由依赖于React Router,React Router保持UI和与URL的同步。它拥有简...

  • vue-router

    前端路由的基本原理 vue-router的基本使用 命名路由 路由参数 嵌套路由

  • react路由基础(Router、Link和Route)

    react路由基础(Router、Link和Route) Router:Router我们可以把它看做是react路...

网友评论

      本文标题:前端路由原理和React Router

      本文链接:https://www.haomeiwen.com/subject/jkizeltx.html