React 教程第十篇 —— 路由(3.0)

前端之家收集整理的这篇文章主要介绍了React 教程第十篇 —— 路由(3.0)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

路由

通过 URL 映射到对应的功能实现,React 的路由使用要先引入 react-router.js。
注意:
react-router 4.0 以上的版本和 3.0 及以下的版本有很大的差别,本教程使用的是 3.0.2 的版本,后续会更新 4.0 以上版本的教程。
在使用 npm 安装时默认是安装最新版本,如果安装的版本是最新的,而使用上用的是 3.0 版本的用法,则会报错。
所以在 npm 安装时要指定版本 npm install react-router@3.0.2 --save-dev

路由背景-SPA

传统的前端基本都是通过页面之间跳转来实现各功能模块的切换,这种做法会导致一个项目下来存在大量的 html 页面,而且每个页面都有一大堆的静态资源文件需要引入,在性能一直被垢病。后来有了随着 ajax 的普及,还有 jQuery 对 ajax 的封装后的便捷使用,开发者会大量的使用 ajax 来加载一个 html 页面当前页面的某个容器当中来实现无刷新加载,但依然没有解决大量存在 html 页面和每个页面加载大量的静态资源文件而导致性能上的问题。随着移动互联网的普及,移动端对页面加载的性能要求和流量的限制越来越高,所以主流的前端框架都往 SPA 方向靠齐。
SPA,Single Page Application 的缩写,单页面应用,其目的是整个应用程序只有一个 html 页面,结合构建 webpack 的统一打包思想,把所有静态资源文件打包成一个 js 文件,在唯一的一个 html 页面引用,从而真正意义上实现一个 html 文件,一个 js 文件完成一个应用的构想。
SPA 优化了静态加载的性能,但一个应用程序还是有很多的功能模块,功能模块之间的切换,就变成了组件之间的切换,所以到目前为止基本上主流的前端框架都会有路由和组件两个概念,而且实现思想都是一致的。

路由引用与使用

  1. //es5
  2. var {Router,Route,hashHistory,Link,IndexRoute,browserHistory} = require("react-router");
  3.  
  4. //es6
  5. import {Router,browserHistory} from 'react-router';
  6.  
  7. //es5 和 es6 的使用都是一样的
  8. <Link to="/">Root</Link>
  9. <Router>
  10. <Route path='/' component={RootComponent}/>
  11. </Router>
  12.  
  13. //使用 `<script>` 标签
  14. <script src="../js/ReactRouter.js"></script>
  15. <ReactRouter.Link to="/">Root</ReactRouter.Link>
  16. <ReactRouter.Router>
  17. <ReactRouter.Route path='/' component={RootComponent}/>
  18. </ReactRouter.Router>

路由组件与属性

Link

  • 用于路由之间跳转功能等同于 a 标签
  • 属性 to 等同于 a 标签href
  • <Link to="/page">page</Link>,作用等同于 <a href="#/page">page</a>

Router

  • 是最外层的路由组件,整个 Application 仅一个。
  • 属性 history 有两个属性值:

    • hashHistory 路由将通过URL的hash部分(#)切换,推荐使用。
    • <Router history={hashHistory}> 对应的 URL 形式类似 example.com/#/some/path
    • browserHistory 这种情况需要对服务器改造。否则用户直接向服务器请求某个子路由,会显示网页找不到的404错误
    • <Router history={browserHistory}> 对应的 URL 形式类似 example.com/some/path。

Route 组件的属性

  • Route 是组件 Router 子组件,可以通过嵌套 route 来实现路由嵌套。
  • 属性 path:指定路由的匹配规则,这个属性是可以省略的,这样的话,不管路径是否匹配,总是会加载指定组件。
  • 属性 component:指当 URL 映射到路由的匹配规则时会渲染对应的组件。
  • <Route path="/" component={RootComponent}/> 当 URL 为 example.com/#/ 时会渲染组件 RootComponent
  • <Route path="/page1" component={Page1Component}/> 当 URL 为 example.com/#/page1 时会渲染组件 Page1Component

基本用法

  1. import React from 'react'
  2. import ReactDOM from 'react-dom'
  3. import {Router,browserHistory} from 'react-router'
  4.  
  5. const html = (
  6. <ul>
  7. <li><Link to="/">Root</Link></li>
  8. <li><Link to="/page">page</Link></li>
  9. </ul>
  10. )
  11.  
  12. class RootComponent extends React.Component{
  13. render(){
  14. return (
  15. <div>
  16. <h1>RootComponent</h1>
  17. {html}
  18. </div>
  19. )
  20. }
  21. }
  22.  
  23. class PageComponent extends React.Component{
  24. render(){
  25. return (
  26. <div>
  27. <h1>PageComponent</h1>
  28. {html}
  29. </div>
  30. )
  31. }
  32. }
  33.  
  34. ReactDOM.render(
  35. <Router history={hashHistory}>
  36. <Route path='/' component={RootComponent}/>
  37. <Route path='/page' component={PageComponent}/>
  38. </Router>,document.getElementById('app')
  39. )

效果预览

路由参数

  • 路由的参数传递是通过 Route 组件的 path 属性来指定的。
  • 参数值可通过 this.props.params.paramName获取
  • :paramName

    • 匹配URL的一个部分,直到遇到下一个/、?、#为止。
    • <Route path="/user/:name">
    • 匹配 URL:/#/user/sam,参数 sam 为必须存在。
    • this.props.params.name 的值为 sam。
  1. import React from 'react'
  2. import ReactDOM from 'react-dom'
  3. import {Router,browserHistory} from 'react-router'
  4.  
  5. class UserComponent extends React.Component{
  6. render(){
  7. return (
  8. <div>
  9. <h3>UserComponent 单个参数 </h3>
  10. <p>路由规则:path='/user/:username'</p>
  11. <p>URL 映射:{this.props.location.pathname}</p>
  12. <p>username:{this.props.params.username}</p>
  13. </div>
  14. )
  15. }
  16. }
  17. ReactDOM.render(
  18. <Router history={hashHistory}>
  19. <Route path='/user/:username' component={UserComponent}/>
  20. </Router>,document.getElementById('app')
  21. )
  • (:paramName)

    • 表示URL的这个部分是可选的。
    • <Route path="/order(/:orderid)">
    • 匹配 URL:/#/order,this.props.params.orderid 获取的值为 undefined。
    • 匹配 URL:/#/order/001,this.props.params.orderid获取参数的值为 001。
  1. import React from 'react'
  2. import ReactDOM from 'react-dom'
  3. import {Router,browserHistory} from 'react-router'
  4.  
  5. class UserComponent extends React.Component{
  6. render(){
  7. return (
  8. <div>
  9. <h3>OrderComponent 可选参数 </h3>
  10. <p>路由规则:path='/order(/:orderid)'</p>
  11. <p>URL 映射:{this.props.location.pathname}</p>
  12. <p>orderid:{this.props.params.orderid}</p>
  13. </div>
  14. )
  15. }
  16. }
  17. ReactDOM.render(
  18. <Router history={hashHistory}>
  19. <ReactRouter.Route path='/order(/:orderid)' component={UserComponent}/>
  20. </Router>,document.getElementById('app')
  21. )
  • *.*

    • 匹配任意字符,直到模式里面的下一个字符为止。匹配方式是非贪婪模式。
    • <Route path="/all1/*.*">
    • this.props.params 获取的参数为一个固定的对象: {splat: [*,*]}
    • 匹配 URL:/all1/001.jpg,参数为 {splat: ['001','jpg']}
    • 匹配 URL:/all1/001.html,参数为 {splat: ['001','html']}
  • *

    • 匹配任意字符,直到模式里面的下一个字符为止。匹配方式是非贪婪模式。
    • <Route path="/all2/*">
    • this.props.params 获取的参数为一个固定的对象: {splat: '*'}
    • 匹配 URL:/all2/,参数为 {splat: ''}
    • 匹配 URL:/all2/a,参数为 {splat: 'a'}
    • 匹配 URL:/all2/a/b,参数为 {splat: 'a/b'}
  • **

    • 匹配任意字符,直到下一个/、?、#为止。匹配方式是贪婪模式。
    • <Route path="/**/*.jpg">
    • this.props.params 获取的参数为一个固定的对象: {splat: [**,*]}
    • 匹配 URL:/all3/a/001.jpg,参数为 {splat: ['a','001']}
    • 匹配 URL:/all3/a/b/001.jpg,参数为 {splat: ['a/b','001']}

效果预览

IndexRoute

当访问一个嵌套路由时,指定默认显示的组件

AppComponent.js

  1. import React from 'react'
  2.  
  3. export default class AppComponent extends React.Component{
  4. render(){
  5. return <div>{this.props.children}</div>
  6. }
  7. }

LoginComponent.js

  1. import React,{Component} from 'react'
  2.  
  3. export default class LoginComponent extends Component{
  4. login(){}
  5. render(){
  6. return <h1>Login</h1>
  7. }
  8. }

HomeComponent.js

  1. import React,{Component} from 'react'
  2.  
  3. export default class HomeComponent extends Component{
  4. login(){}
  5. render(){
  6. return <h1>Home</h1>
  7. }
  8. }

Router.js

  1. import React from 'react'
  2. import {Route,IndexRoute} from 'react-router'
  3.  
  4. import AppComponent from '../components/app/app'
  5. import HomeComponent from '../components/home/home'
  6. import LoginComponent from '../components/login/login'
  7.  
  8. const routes = (
  9. <Route path="/" component={AppComponent}>
  10. <IndexRoute component={HomeComponent} />
  11. <Route path="login" component={LoginComponent} />
  12. <Route path="home" component={HomeComponent} />
  13. </Route>
  14. )
  15.  
  16. export default routes;
  • 如果没有加IndexRoute,则在访问 http://localhost/#/页面是空白的
  • 访问 http://localhost/#/login 才会显示内容
  • 加上 IndexRoute,在访问http://localhost/#/时会默认渲染HomeComponent

模块化

可利用组件Router属性routes来实现组件模块化

router.js

  1. import React from 'react'
  2. import ReactDOM from 'react-dom'
  3.  
  4. import {Route,Router,hashHistory} from 'react-router'
  5.  
  6. import AppComponent from '../components/app/app'
  7. import HomeComponent from '../components/home/home'
  8. import LoginComponent from '../components/login/login'
  9.  
  10. const routes = (
  11. <Route path="/" component={AppComponent}>
  12. <IndexRoute component={HomeComponent} />
  13. <Route path="login" component={LoginComponent} />
  14. <Route path="home" component={HomeComponent} />
  15. </Route>
  16. )
  17.  
  18. ReactDOM.render(
  19. <Router history={hashHistory} routes={routes} />,document.getElementById('app')
  20. )

编程式导航

  • 普通跳转 this.props.router.push('/home/cnode')
  • 带参数跳转this.props.router.push({pathname: '/home/cnode',query: {name: 'tom'}})

路由钩子函数

每个路由都有enterleave两个钩子函数,分别代表用户进入时和离开时触发。

onEnter

进入路由/home前会先触发onEnter方法,如果已登录,则直接next()正常进入目标路由,否则就先修改目标路径replace({ pathname: 'login' }),再next()跳转

  1. let isLogin = (nextState,replace,next) => {
  2. if(window.localStorage.getItem('auth') == 'admin'){
  3. next()
  4. } else {
  5. replace({ pathname: 'login' })
  6. next();
  7. }
  8. }
  9. const routes = (
  10. <Route path="/" component={AppComponent}>
  11. <Route path="login" component={LoginComponent} />
  12. <Route path="home" component={HomeComponent} onEnter={isLogin}/>
  13. </Route>
  14. )

onLeave

对应的setRouteLeaveHook方法,如果return true则正常离开,否则则还是停留在原路由

  1. import React from 'react'
  2. import {Link} from 'react-router'
  3.  
  4. export default class Component1 extends React.Component{
  5. componentDidMount(){
  6. this.props.router.setRouteLeaveHook(
  7. this.props.route,this.routerWillLeave
  8. )
  9. }
  10. routerWillLeave(){
  11. return '确认要离开?'
  12. }
  13. render(){
  14. return (
  15. <div>
  16. <Link to="/login">Login</Ling>
  17. </div>
  18. )
  19. }
  20. }

猜你在找的React相关文章