美文网首页
react的react-router(路由)-08

react的react-router(路由)-08

作者: 逝去丶浅秋 | 来源:发表于2019-12-10 18:05 被阅读0次

    可以参看官方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的话,在页面组件中就可以直接使用公共路由组件的方法。


    写在最后:

    • 如果文章中有错误或是表达不准确的地方,欢迎大家评论中指正,以便我完善。
    • 文章我也会根据所学到新的知识不断更新。

    相关文章

      网友评论

          本文标题:react的react-router(路由)-08

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