美文网首页
React路由

React路由

作者: hellomyshadow | 来源:发表于2018-11-14 08:13 被阅读0次

    react-router React路由,让父组件动态去挂载不同的子组件,以目前最新的4.x为例;

    • 前端路由的实现:history库,管理浏览器会话历史的工具库。本质上还是包装了原生BOM中的 window.historywindow.location.hash
    • 核心组件:<BrowserRouter>、<HashRouter>、<Route>、<Redirect>、<Link>、<NavLink>、<Switch>
    • 对象:history、match、withRouter

    引入路由之后,可以把组件分为两类:普通组件(components目录)、路由组件(views目录)

    基本配置

    1. 安装react-router-dom模块:npm install react-router-dom --save
    2. 在根组件App.js中引入路由相关的组件,加载的子组件包括Home.js、News.js、Product.js、NotFound.js
      import { BrowserRouter, Route, NavLink, Switch } from 'react-router-dom'
      render() {
          return(<BrowserRouter>
              <div>
                  <header>
                      <NavLink to="/">首页</NavLink>
                      <NavLink to="/news">新闻</NavLink>
                      <NavLink to="/product">商品</NavLink>
                      <NavLink to="/notfound">一个不存在的路由</NavLink>
                  </header>
                  <Switch>
                      <Route exact path="/" component={Home} />
                      <Route path="/news" component={News} />
                      <Route path="/product" component={Product} />
                      <Route component={NotFound} />  // 404组件
                  </Switch>
              </div>
          </BrowserRouter>)
      }
      
      • 在根组件中,把Home组件的路由配置为path="/",表示默认加载Home组件;
      • exact:表示严格匹配模式,必须完全匹配,如果设置为false,每次都会匹配 path="/" 的路由;
      • 404组件不需要声明任何path,且必须放在最后面,当上面的所有路由都没有匹配时,则匹配404路由。
    3. Redirect 表示重定向,可用于指定默认路由
      import { BrowserRouter, Route, NavLink, Switch, Redirect } from 'react-router-dom'
      render() {
          return(<BrowserRouter>
              <div>
                  <header>
                      <NavLink to="/">首页</NavLink>
                      <NavLink to="/news">新闻</NavLink>
                      <NavLink to="/product">商品</NavLink>
                  </header>
                  <Switch>
                      <Route path="/home" component={Home} />
                      <Route path="/news" component={News} />
                      <Route path="/product" component={Product} />
                      <Redirect to="/home" />  //默认路由,加载Home组件
                  </Switch>
              </div>
          </BrowserRouter>)
      }
      
    4. 一个项目中只有一个<BrowserRouter>,所以 <BrowserRouter> 包裹根组件即可!
    5. <NavLink><Route>必须包裹在<BrowserRouter>中,且<BrowserRouter>只能有一个直接子节点;
    6. NavLinkLink:它们最终都被解析为HTML中的<a>,但内部会阻止浏览器的默认行为;
      • to 属性用于指定跳转的路由,也可以是一个对象
        <Link to={{ pathname: '/courses', search: '?sort=name', hash: '#the-hash', state: { fromDashboard: true } }}/>
        
      • <NavLink><Link>的一个特定版本,它会在匹配上当前的url时给已经渲染的元素添加参数;
      • <NavLink> 上的属性:activeClassName、activeStyle、exact、strict ...
        <NavLink className="normal" activeClassName="active" to="/news">
        //NavLink的默认样式className="",匹配时的激活样式:activeClassName="" 或 activeStyle={}
        
      • 自定义NavLinkMyNavLink.jsx,统一使用一个activeClassName
        import React, {Component} from 'react'
        import {NavLink} from 'react-router-dom'
        export default class MyNavLink extends Component {
            render() {
                return <NavLink {...this.props} activeClassName='active'>
            }
        }
        
    7. Routepath指定路由,component指定路由对应的组件;
    8. Switch:从上往下匹配时,只要匹配成功,就不会再向下匹配,即只显示与当前路由匹配的Route
    9. <NavLink><Route>可以不在同一个组件中,只要路由匹配,都可以实现路由跳转。

    路由传值

    1. 动态路由传参:<Route path="/info/:id" component={Info} />
      this.state = { id:12 }
      
      1. :id 表示占位符,对应的NavLink
        <NavLink to={`/info/${this.state.id}`}>详情</NavLink>
        
      2. Info.js 组件中获取动态路由的参数idthis.props.match.params
        componentDidMount() {
            let { id } = this.props.match.params
        }
        
    2. GET方式传参
       <Route path="/info" component={Info} />
       <NavLink to={`/info?id=${this.state.id}`}>详情</NavLink>
      
      1. Info.js 组件中,获取参数的对象:this.props.location
         const { search } = this.props.location
        
      2. 但是,GET参数并没有被解析,仍是一个原始字符串:?id=12
      3. 借助第三方模块url解析get参数:npm install url --save
        import url from 'url'  //url模块是node上的内置模块,npm上的url模块并不是node的
        componentDidMount() {
            let { id } = url.parse(this.props.location.search, true).query
        }
        
      4. React不建议使用 ?xxx=xxx的方式传参,而是把 to 设置为对象
        <NavLink to={ { pathname:'/info', id:this.state.id } }>详情</NavLink>
        
    3. React解析原始HTML字符串:dangerouslySetInnerHTML属性
      this.state = { content: '<p>原始HTML字符串</p>' }
      <div dangerouslySetInnerHTML={{__html: this.state.content}}></div>
      

    路由嵌套

    1. User.js 组件是根路由 App.js 的动态子组件,路由名称为/user
      1. User组件中再配置两个动态子组件:Main.jsInfo.js
        import { Route, NavLink, Redirect, Switch } from 'react-router-dom'
        render() {
            return(<div>
                <div className="left">
                    <NavLink to="/user/">个人中心</NavLink>
                    <NavLink to="/user/info">用户详情</NavLink>
                </div>
                <div className="right">
                    <Switch>
                        <Route exact path="/user/" component={Main} />
                        <Route path="/user/info" component={Info} />
                    <Switch>
                </div>
            </div>)
        }
        
      2. User组件的路由为/user,则把子组件Main的路由设置为/user/,表示默认加载Main组件;
      3. 亦或者,Redirect 重定向的方式实现默认加载的路由组件
        render() {
            return(<div>
                <div className="left">
                    <NavLink to="/user/center">个人中心</NavLink>
                    <NavLink to="/user/info">用户详情</NavLink>
                </div>
                <div className="right">
                    <Switch>
                        <Route exact path="/user/center" component={Main} />
                        <Route path="/user/info" component={Info} />
                        <Redirect to='/user/center' />
                    <Switch>
                </div>
            </div>)
        }
        
      4. Redirectto 属性也可以是一个对象:pathname表示路由地址,其他的是参数;
        <Redirect to={ {pathname:'/', state:{foo:'bar'}} } />
        
    2. 动态获取父级的路由,再拼接成自己组件的路由
      <Route exact path={`${this.props.match.url}/`} component={Main} />
      <Route path={`${this.props.match.url}/info`} component={Info} />
      

    JS控制路由跳转

    1. 借助对象:this.props.history 中的方法
    2. push()、replace()、goBack()、goForward() ......
      this.props.history.push('/home/user');
      this.props.history.push({ pathname: '/home/user', state: { foo:'bar' } });
      
    3. 获取传递的参数:this.props.location
      const { foo } = this.props.location.state;
      

    路由守卫

    1. 路由守卫其实就是路由拦截,可以做权限控制,它其实也是一个组件,返回值是一个Route组件;
        class RouteGuard extends Component {
            state = {
                isLogin: false
            }
            render() {
                const {component:Component, ...otherProps} = this.props
                return (
                    <Route {...otherProps} render={props => (
                        //只有已经登录了才允许进入守卫路由对应的组件,没有登录则重定向到登录页
                        this.state.isLogin ? <Component {...props}></Component> : 
                        (<Redirect to={{ pathname:'/login', state:{from:props.location.pathname} }} />)
                    )}></Route>
                )
            }
        }
    
    1. 在需要控制权限的地方,应用路由守卫
        render() {
            return(<BrowserRouter>
                <div>
                    <header>
                        <NavLink to="/">首页</NavLink>
                        <NavLink to="/news">新闻</NavLink>
                        <NavLink to="/mine">我的</NavLink>
                    </header>
                    <Switch>
                        <Route exact path="/" component={Home} />
                        <Route path="/news" component={News} />
                        <RouteGuard path="/mine" component={Mine} />  // 应用路由守卫
                    </Switch>
                </div>
            </BrowserRouter>)
        }
    

    路由的模块化

    1. 用一个数组管理项目中的所有路由,在把这个数组放在一个独立的JS文件中
      1. router.js 中引入相关组件,管理路由
        const routes = [
            { path:'/', component:Home, exact:true },
            { path:'/user', component:User }
        ]
        export default routes;
        
      2. 在根组件App中引入路由模块
        import routes from './route/router.js'
        render(){
            return(<BrowserRouter>
                <header>
                    <NavLink to="/">首页</NavLink>
                    <NavLink to="/user">用户</NavLink>
                </header>
                {
                    routes.map((route, key) => {
                        if(route.exact) {
                            return <Route key={key} exact path={route.path} component={route.component} />
                        } else {
                            return <Route key={key} path={route.path} component={route.component} />
                        }
                    })
                }
            </BrowserRouter>)
        }
        
    2. 嵌套路由的管理
      1. router.js
        const routes = [
            { path:'/', component:Home, exact:true },
            { path:'/user', component:User,
                routes:[
                    { path:'/user/', component:Main }, 
                    { path:'/user/info', component:Info }
                ]
            }
        ]
        
      2. 在根组件App中,通过<Route>render 属性,把子路由传递给子组件
        <Route key={key} path={route.path} render={props => (
            <route.component {...props} routes={route.routes} />
        )} />
        
      3. User组件中获取子路由:this.props.routes
        render() {
            return(<div>
                <div className="left">
                    <NavLink to="/user/">个人中心</NavLink>
                    <NavLink to="/user/info">用户详情</NavLink>
                </div>
                <div className="right">
                    {
                        this.props.routes.map((route, key) => {
                            return <Route key={key} exact path={route.path} component={route.component} />
                        })
                    }
                </div>
            </div>)
        }
        
    3. 子路由的<Route />上可以都加上 exact 属性,而根路由的<Route />上不行!

    相关文章

      网友评论

          本文标题:React路由

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