react的react-router(路由)-08

可以参看官方github里面的文档。
官方github地址:https://github.com/ReactTraining/react-router
往下翻到如图所示位置,然后选择对应版本的API Docs

一、react-router的安装和使用

1、react-router的安装

安装命令:

npm install react-router-dom --save

引入:

import { BrowserRouter as Router,Switch,Route,Link } from "react-router-dom";
2、react-router的使用

使用<Router></Router>标签包裹,在里面使用<Route></Route>:

<Router>
    <div>
        <Link to="/">首页</Link><br/>
        <Link to="/tool">工具</Link>
        <hr/>
        <Route exact path="/">
            <Index/>
        </Route>
        <Route path="/tool">
            <Tool/>
        </Route>
        {/* <Route exact path="/" component={Index}/>
        <Route path="/tool" component={Tool}/> */}
    </div>
</Router>

如上面的例子<Route />的两种写法都可以:

//第一种写法
<Route path="/tool">
    <Tool/>
</Route>
//第二种写法
<Route path="/tool" component={Tool}/>

Route中的exact属性:表示严格匹配,一般来说,react路由会匹配所有匹配到的路由组件,exact能够使得路由的匹配更严格一些。
exact的值为bool型,为true是表示严格匹配,为false时为正常匹配。

<Route path='/' component={Index} />
<Route path='/tool' component={Tool}>
//这种情况下,如果匹配路由path='/tool',那么会把Index组件也会展示出来。
<Route exact path='/' component={Index} />
<Route path='/tool' component={Tool} />
//添加exact后,path='/',则会显示Index组件;
path='/tool',则只会显示Tool组件,不会显示Index组件
3、<Redirect />重定向跳转
render(){
  if(this.state.flag){
    return <Redirect to={{pathname:"/selectCity"}} />
  }
  return(
  );
}

当this.state.flag为true时,通过<Redirect />标签来实现跳转,标签中的to属性为要跳转到哪里,pathname就是要跳转的路径。

二、动态路由及get传值

一个页面跳转到另外一个页面进行传值:get传值、动态路由、LocalStorage

1、动态路由传值

动态路由就是在匹配路径path的后面加上冒号+参数,如path="/info/:id"。用一个共同的信息组件,根据不同的需要动态渲染不同的内容。

  • 先需要导入模块
import { BrowserRouter as Router,Switch,Route,Link } from "react-router-dom";
  • 动态路由标签
    需要用<Router></Router>标签包裹起来作为根标签,在标签中使用<Link />、<Route />和<Switch />标签。
  • 动态路由的使用
RouterIndex.js

import React from 'react';
//引入模块
import { BrowserRouter as Router,Switch,Route,Link } from "react-router-dom";
//引入组件
import Product from './Product';
import Info from './Info';
import Index from './Index';
class RouterIndex extends React.Component {
    constructor(props) {
        super(props);
        this.state = {  };
    } 
    render() {
        return (
            <Router>
                <div>
                    <Link to="/">index页面</Link>
                    <Link to="/product">Product页面</Link>
                    <hr/>
                    <Switch>
                        <Route exact path="/" component={Index} />
                        <Route path="/product" component={Product} />
                    </Switch>
                    //Info页面根据需要看写在哪
                    {/* <Route path="/info/:aid" component={Info} /> */}
                </div>
            </Router>
        );
    }
}
export default RouterIndex;

<Link>标签:
配置路由,这里需要注意<Link>标签的L是大写的,这是react-router中的,写错会报错。

<Link to="/product">Product页面</Link>
标签中的to="/product"这个是指向下面配置的路由路径,和<Route>中的path中的路径相对应。

<Route>标签:

<Route exact path="/" component={Index} />
标签中的path和上面<Link>标签中to里面的路径对应,
component是配置要跳转到的组件

我们在<Route>标签中看到有个exact属性,关于这个要和<Switch>标签一起讲。我们在使用时不使用<Switch>标签也是可以的。

exact是:精准匹配,意思就是当url和该<Route>标签中的path属性进行精确比对后,完全相同才会被渲染。

<Switch>是:渲染第一个被location匹配到的并且作为子元素的<Route>或者<Redirect>。

关于<Switch>的坑

如果只是用这个标签不添加exact属性的话,当path="/product"的时候只会显示index页面。所以需要的话还需要配上exact属性使用。

对于不加<Switch>和exact的话,对于上面代码中的路由:
如果使用path="/",则会显示index页面;
如果使用path="/product",则会显示index页面和product页面;

Product.js

import React from 'react';
import { BrowserRouter as Router,Switch,Route,Link } from 'react-router-dom';
import Info from './Info';
class Product extends React.Component {
    constructor(props) {
        super(props);
        this.state = { 
            list:[{id:'1',info:'aaa'},{id:'2',info:'bbb'},{id:'3',info:'ccc'}]
         };
    }
    render() {
        return (
            <Router>
            <div>
                <ul>
                    {this.state.list.map((value,key)=>{
                        return(
                            <li key={key}>
                                <Link to={`/info/${value.id}`}>info:{value.info}</Link>
                            </li>
                        )
                    })}
                </ul>
                <Route path="/info/:id" component={Info} />
            </div>
            </Router>
        );
    }
}
export default Product;

在projuct页面模拟产品数据,然后使用map方法遍历出来,遍历后我们需要给它们添加上Link,然后可以点击路由到产品信息Info页面。

<Link to={`/info/${value.id}`}>info:{value.info}</Link>
标签上to的值除了路径,还需要添加上要携带的参数
在写法上如代码所示{`/路径/${值}`}:特殊符号是英文状态esc下面的那个键

我们需要在<Link>对应的路由的path上也是这种路径+参数的格式,如下:

<Route path="/info/:id" component={Info} />
这里我们只需要路径+冒号+加参数名字即可

当路由到Info页面后,传的值其实存在props里面:

Info.js

<span>收到传值--->id:{this.props.match.params.id}</span>
传的值保存在props下的match下的params里面,我们直接获取即可
2、动态路由get传值

因为我们获取到的参数是这样的http://localhost:3000/info?id=2,获取的结果是?id=2,我们可以自己使用js对参数进行解析,这里介绍个模块来进行解析。

  • 安装url模块:
cnpm install url --save
import url from 'url';//引入url模块
  • 使用
<Route path="/info" component={Info} />
<Link to={`/info?id=${value.id}`}></Link>
如上写法

在页面上我们还是需要在props里面获取值:

this.props.location.search
获取的结果:?id=2

我们可以使用url模块对齐进行解析:

url.parse(this.props.location.search,true)
第二个参数传入true,则是 query:{id: "2"} 的格式,接下来我们获取id值:
var query = url.parse(this.props.location.search,true).query;
var id = query.id //获取到id值

需要注意的是:我们在componentDidMount里完成对数据的请求时,这个时候会在componentDidMount之前渲染,对于<img/>标签来说,这个时候的路径是不存在的,这个时候会有404,所以我们需要先判断:

如果存在img_url就使用标签,如果不存在就返回""
{this.state.list.img_url?<img src={`${this.state.domain}${this.state.list.img_url}`} />:""}

三、嵌套路由及传值


实现如上图效果,左侧的main、info和右侧的内容显示在同一个组件中布局,先来个简单的例子,下面是代码:

export default class QtRouter extends React.Component {
    constructor(props){
        super(props);
        this.state = {
            status:1
        }
    }
    setBtnStyle=(num)=>{
        console.log("setBtnStyle方法执行");
        this.setState({
            status:num
        });        
    }
    render() { 
        return(
            <div className="user">
                <div className="content">
                    <div className="left">
                        <Button type={1 === this.state.status ? "primary" : ""} onClick={this.setBtnStyle.bind(this,1)}><Link to="/qtRouter/">main</Link></Button><br/><br/>
                        <Button type={2 === this.state.status ? "primary" : ""} onClick={this.setBtnStyle.bind(this,2)}><Link to="/qtRouter/info">info</Link></Button>
                    </div>
                    <div className="right">
                        <Route exact path="/qtRouter/" component={Main}/>
                        <Route path="/qtRouter/info" component={Info}/>
                    </div>
                </div>
            </div>
        );
    }
}

左侧放<Link/>链接,右侧部分放入<Route/>路由。

上面是简单的嵌套路由的例子,再看下图的例子:



这个导航有两个按钮,分别对应两个页面,个人中心的页面中包含main和info,分别对应两个页面,main和info是个人中心的子路由。

//routes.js
//路由配置文件
import Login from "../components/Login";
import QtRouter from "../components/QtRouter";
import Main from "../components/qtRouterComponent/Main";
import UseInfo from "../components/qtRouterComponent/UseInfo";
const routes = [
    //登录的route配置
    {path:"/login",component:Login},
    //个人中心的route配置
    {path:"/qtRouter",component:QtRouter,
        routes:[
            {path:"/qtRouter",component:Main,exact:true},
            {path:"/qtRouter/userInfo",component:UseInfo}
        ]
    }
];
export default indexRouteConfig;

上面是路由的配置routes.js,相当于之前的<Route path="/path" component="/component"/>里面path和component的值。这个文件上方需要导入用到的组件。

//CommonRoute.js
import React from 'react';
import { Route } from "react-router-dom";
export default function CommonRoute (route){
    if (route.exact) {
      return (
        <Route exact path={route.path} render={props=>(
          //此处给子路由传值{...props}
          <route.component {...props} routes={route.routes} />
        )} />
      );
    }else{
      return (
        <Route path={route.path} render={props=>(
          <route.component {...props} routes={route.routes} />
        )} />
      );
    }
}

上面是一个公共的路由组件,这个函数接收的值(route)中包含了上面routes.js的内容,这个函数组件作用相当于是渲染成<Route path="/path" component="/component"/>,如demo中注释处给子路由传值。
在写法上使用了render,此写法相当于是component="/component,关于render的写法如下所示:

render={props=>(
          <route.component {...props} routes={route.routes} />
        )

下面是登录和个人中心的组件:

//RouterIndex.js
import React, { Component } from 'react';
import { BrowserRouter as Router,Link } from "react-router-dom";
import routes from '../router/routes';
import CommonRoute from './CommonRoute';
export default class RouterIndex extends Component {
    constructor(props) {
        super(props);
        this.state = { };
    }   
    render() {
        return (
            <Router>
                <Link to="/login">登录</Link>
                <Link to="/qtRouter">个人中心</Link>
                <hr/>
                {
                    routes.map((route,key)=>{
                         return <CommonRoute key={key} {...route} />
                    })
                 }
            </Router>
        );
    }
}

此组件中导入我们写的公共路由组件CommonRoute.js和路由配置routes.js,接下来使用map遍历routes获取值,通过公共路由组件来渲染<Route/>:

{
    //遍历routes中的数据
    routes.map((route,key)=>{
       //使用CommonRoute公共组件,将route值传入,即{...route}
        return <CommonRoute key={key} {...route} />
    })
}

下面是main和info组件的demo:

//QtRouter .js
import React from 'react';
import { Link } from "react-router-dom";
import CommonRoute from './CommonRoute';
export default class QtRouter extends React.Component {
    constructor(props){
        super(props);
        this.state = { }
    }   
    render() {       
        return(
            <Router>
                <Link to="/qtRouter">main</Link>
                <Link to="/qtRouter/userInfo">info</Link>
                {
                    //我们使用this.props.routes来获取配置文件routes.js中子路由的数据
                    this.props.routes.map((route,key)=>{
                        return <CommonRoute key={key} {...route} />
                    })
                }
            </Router>
        );
    }
}

我们使用this.props来获取传入的数据,数据是保存在this.props中的。

如果不抽离公共路由组件CommonRoute.js的话,在页面组件中就可以直接使用公共路由组件的方法。


写在最后:

  • 如果文章中有错误或是表达不准确的地方,欢迎大家评论中指正,以便我完善。
  • 文章我也会根据所学到新的知识不断更新。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容