zoukankan      html  css  js  c++  java
  • react-router v4 学习实践

        最近学习了 react-router v4,根据官方 API 文档和网上资源做了一个简单的路由示例。

        先用官方的工具 create-react-app  初始化一个 react 项目模板,再根据自己的需要修改。

    要实现的路由:

    1. 登录页(/login)

    2. 主页(/home):一级导航

    3. 商品管理(/goods):一级导航

    4. 商品列表(/goods/list):二级导航

    5. 商品品牌(/goods/brand):二级导航

    6. 路由重定向:

        (1)未登录时,地址栏输入主域名(localhost:3000),页面重定向到登录页;否则,重定向到主页。

        (2)点击一级导航“商品管理”时,重定向到其下的第一个子导航“商品列表”。

        (3)退出后,重定向到登录页。

    项目结构:

    ├── app
    │   ├── public
    │   │   ├── favicon.ico
    │   │   ├── index.html
    │   │   └── manifest.json
    │   ├── src
    │   │   ├── assets
    │   │   │   ├── app.css
    │   │   │   └── logo.svg
    │   │   ├── common
    │   │   │   └── RouteWithSubRoutes.js
    │   │   ├── modules
    │   │   │   ├── asideContainer
    │   │   │   │   └── Goods.js
    │   │   │   ├── container
    │   │   │   │   ├── Container.js
    │   │   │   │   ├── Header.js
    │   │   │   │   └── Home.js
    │   │   │   ├── error
    │   │   │   │   └── NotFound.js
    │   │   │   ├── goods
    │   │   │   │   ├── Brand.js
    │   │   │   │   └── List.js
    │   │   │   ├── login
    │   │   │   │   └── Login.js
    │   │   ├── index.js
    │   │   ├── Routes.js
    │   ├── .gitignore
    │   ├── package-lock.json
    │   ├── package.json
    │   └── README.md

    路由配置(src/Routes.js):

    import React from 'react'
    import {
      BrowserRouter as Router,
      Switch,
      Route
    } from 'react-router-dom'
    
    import RouteWithSubRoutes from './common/RouteWithSubRoutes.js'
    import NotFound from './modules/error/NotFound.js'
    import Login from './modules/login/Login.js'
    import Container from './modules/container/Container.js'
    import Home from './modules/container/Home.js'
    import Goods from './modules/asideContainer/Goods.js'
    import List from './modules/goods/List.js'
    import Brand from './modules/goods/Brand.js'
    
    const routes = [
      {
        path: '/home',
        component: Home
      },
      {
        path: '/goods',
        component: Goods,
        children: [
          {
            path: '/goods/list',
            component: List
          },
          {
            path: '/goods/brand',
            component: Brand
          }
        ]
      }
    ]
    
    export default () => (
      <Router>
        <Switch>
          <Route path='/login' component={Login} />
          <Container>
            <Switch>
              {routes.map((route, i) => (
                <RouteWithSubRoutes key={i} {...route} />
              ))}
              <Route component={NotFound} />
            </Switch>
          </Container>
        </Switch>
      </Router>
    )

        重定向需要用到 Redirect 组件,但是我的经验就是,Redirect 不要与 Route 作为同级兄弟一起使用,否则页面会保持在 Redirect 指定的路由,而不能跳到其它的路由:

    this.props.history.push 指定的路由就会无效。

        RouteWithSubRoutes 参考的是官方的的示例。它是一个函数,接收一个对象作为参数,并返回一个(子)路由。在这里它用于渲染一级导航。

    登录(src/modules/login/Login.js):

    import React, { Component } from 'react'
    import { Redirect } from 'react-router-dom'
    
    export default class Login extends Component {
      constructor(props) {
        super(props)
        this.state = {
          loggedIn: localStorage.getItem('loggedIn'),
          username: 'anonymous',
          password: '123'
        }
    
        this.onInputChange = this.onInputChange.bind(this)
        this.onSubmit = this.onSubmit.bind(this);
      }
    
      onInputChange(event) {
        const target = event.target
        const name = target.name
        const value = target.value
    
        this.setState({
          [name]: value
        })
      }
    
      onSubmit(event) {
        if (this.state.username && this.state.password) {
          localStorage.setItem('loggedIn', true)
          localStorage.setItem('username', this.state.username)
          this.setState({loggedIn: true})
          this.props.history.push('/home')
        }
      }
    
      render() {
        if (this.state.loggedIn && this.props.location.pathname === '/login') {
          return (
            <Redirect to='/home' />
          )
        }
    
        return (
          <div className='login-wrap'>
            <h2>登 录</h2>
            <div className='field-box'>
              <label className='control-label'>用户名:</label>
              <input type='text' name='username' value={this.state.username} onChange={this.onInputChange} />
            </div>
            <div className='field-box'>
              <label className='control-label'>密  码:</label>
              <input type='password' name='password' value={this.state.password} onChange={this.onInputChange} />
            </div>
            <div className='field-box'>
              <label className='control-label'></label>
              <button type='button' onClick={this.onSubmit}>登 录</button>
            </div>
          </div>
        )
      }
    }

    将用户名写入 localStorage,再通过 this.props.history.push('/home') 跳转到主页。

    Container组件(src/modules/container/Container.js):

    import React, { Component } from 'react'
    import { Redirect } from 'react-router-dom'
    
    import Header from './Header'
    
    class Container extends Component {
      constructor() {
        super()
        this.state = {
          loggedIn: localStorage.getItem('loggedIn'),
          test: 'it is a testing'
        }
      }
    
      render() {
        if (!this.state.loggedIn) {
          return (
            <Redirect to='/login' />
          )
        } else if (this.props.location.pathname === '/') {
          return (
            <Redirect to='/home' />
          )
        }
    
        return (
          <div>
            <Header {...this.state} />
            <div className='main-layout'>
              {this.props.children}
            </div>
          </div>
        )
      }
    }
    
    export default Container

    判断用户是否登录,再通过 Redirect 重定向到相应的路由。

    this.props.children 用于获取 Container 的子组件。

    头部(src/modules/container/Header.js):

    import React, { Component } from 'react'
    import { NavLink, Redirect } from 'react-router-dom'
    
    export default class Header extends Component {
      constructor(props) {
        super(props)
        this.state = {
          loggedIn: localStorage.getItem('loggedIn')
        }
      }
    
      onLogout = () => {
        localStorage.setItem('loggedIn', '')
        this.setState({loggedIn: false})
      }
    
      render() {
        if (!this.state.loggedIn) {
          return (
            <Redirect to='/login' />
          )
        }
    
        return (
          <header className='fixed-top'>
            <div className='pull-left'>
              <h1>管理平台</h1>
              <NavLink to='/home' exact>主页</NavLink>
              <NavLink to='/goods'>商品管理</NavLink>
            </div>
            <div className='pull-right'>
              <div className='header-info'>
                欢迎您,{localStorage.getItem('username')}
                <span style={{marginLeft: 10}}>|</span>
                <a className='logout' onClick={this.onLogout}>退出</a>
              </div>
            </div>
          </header>
        )
      }
    }

    退出后,清空 localStorage 中的 loggedIn,并重定向到登录页

    <Redirect to='/login' />

    商品管理(src/modules/asideContainer/Goods.js):

    import React from 'react'
    import { NavLink, Route, Redirect } from 'react-router-dom'
    
    import RouteWithSubRoutes from '../../common/RouteWithSubRoutes.js'
    
    export default ({ routes, path }) => (
      <div>
        <div className='aside-nav'>
          <NavLink to="/goods/list">商品列表</NavLink>
          <NavLink to="/goods/brand">商品品牌</NavLink>
        </div>
    
        {
          routes.map((route, i) => {
            return (
              <RouteWithSubRoutes key={i} {...route}/>
            )
          })
        }
    
        <Route exact path='/goods' render={() => (
          <Redirect to='goods/list' />
        )} />
      </div>
    )

    同样用到了 RouteWithSubRoutes, 在这里它用于渲染二级导航。

    通过 Route 判断当前页是“商品管理”(exact 用于路由的严格匹配),再用 Redirect 重定向。

    注意,当前路由处于 active 状态,用到的是 NavLink 组件;另一个类似功能的组件是 Link,但没有当前 active 状态。

    回过头去看看 Header 组件:

    <NavLink to='/home' exact>主页</NavLink>
    <NavLink to='/goods'>商品管理</NavLink>

    对于“主页”,添加了 exact 属性,但“商品管理”则没有,为什么?因为当路由跳转到“商品列表”(/goods/list)时,exact 严格匹配 /goods 的结果为 false,模糊匹配的结果才为 true。

     更多细节,详见项目内容。

  • 相关阅读:
    h5 canvas
    css3选择器
    弹性盒模型
    css新增属性
    蒙版 倒影 渐变
    字符串转化为json的三种方法
    Final互评------《弹球学成语》---- 杨老师粉丝群
    Final互评------《飞词》---- 拉格朗日2018
    作业 20181204-4 互评Final版本
    换手
  • 原文地址:https://www.cnblogs.com/caihg/p/7111904.html
Copyright © 2011-2022 走看看