react-路由

1.路由的基本使用

import React, {
    
     Component } from 'react'
import ReactDOM from 'react-dom';
import {
    
     BrowserRouter,Link, Route, NavLink, Switch, Redirect } from 'react-router-dom';
import './normalize.css';

/**
 * 路由的基本使用
 * 1.明确好界面中的导航区和展示区
 * 2.导航区a标签改为Link标签
 *    2.1<Link to="/xxx" >home</Link>
 * 3.展示区写Route标签进行路径匹配
 *    3.1<Route path="/xxx" component={Demo} />
 * 4.<App/>的最外层最好包裹一个<BrowserRouter>或者<HashRouter>
 */
 
/**
 * 路由组件和一般组件的区别
 * 1.路由组件的props对象中会有三个对象(history/location/match)
 * 2.写法不同
 *    2.1一般组件:<Demo/>
 *    2.2路由组件:<Route path="/xxx" component={Demo} />
 * 3.存放位置不同:
 *    3.1:一般组件 components
 *    3.2:路由组件 pages
 */
class Home extends React.Component {
    
    
  render() {
    
    
    return (
      <div>
        home
      </div>
    )
  }
}

class About extends React.Component {
    
    
  render() {
    
    
    return (
      <div>
        about
      </div>
    )
  }
}

class App extends React.Component {
    
    
  state = {
    
    
    msg: 'react-router-dom'
  }
  render() {
    
    
    let {
    
     msg } = this.state;
    return (
      <div className="wrap">
        <h2>{
    
    msg}</h2>
        {
    
    /* 编写路由链接-点击路由改变浏览器地址 */}
        <Link to="/home">home</Link>
        <Link to="/about">about</Link>
        <Switch>
          {
    
    /* 注册路由-根据浏览器地址匹配组件 */}
          <Route path='/home' component={
    
    Home}></Route>
          <Route path='/about' component={
    
    About}></Route>
        </Switch>
      </div>
    )
  }
}

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>, document.querySelector('#root'));

2.NavLink的使用

import React, {
    
     Component } from 'react'
import ReactDOM from 'react-dom';
import {
    
     BrowserRouter,Link, Route, NavLink, Switch, Redirect } from 'react-router-dom';
import './normalize.css';

/**
* NavLink可以实现路由的高亮,通过activeClassName指定类名
* 标签体内容是一个特殊的标签属性
* 通过this.props.children可以获取标签体内容
*/

class Home extends React.Component {
    
    
  render() {
    
    
    return (
      <div>
        home
      </div>
    )
  }
}

class About extends React.Component {
    
    
  render() {
    
    
    return (
      <div>
        about
      </div>
    )
  }
}

class App extends React.Component {
    
    
  state = {
    
    
    msg: 'react-router-dom'
  }
  render() {
    
    
    let {
    
     msg } = this.state;
    return (
      <div className="wrap">
        <h2>{
    
    msg}</h2>
        {
    
    /* NavLink可以通过activeClassName属性节点添加类名 */}
        <NavLink to="/home" activeClassName='active'>home</NavLink>
        <NavLink to="/about" activeClassName='active'>about</NavLink>
        <Switch>
          <Route path='/home' component={
    
    Home}></Route>
          <Route path='/about' component={
    
    About}></Route>
        </Switch>
      </div>
    )
  }
}

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>, document.querySelector('#root'));

3.Switch的使用

  • 通常状态下pathcomponent是一一对应关系
  • Switch可以提高路由的匹配效率(单一匹配)
import React, {
    
     Component } from 'react'
import ReactDOM from 'react-dom';
import {
    
     BrowserRouter,Link, Route, NavLink, Switch, Redirect } from 'react-router-dom';
import './normalize.css';

class Home extends React.Component {
    
    
  render() {
    
    
    return (
      <div>
        home
      </div>
    )
  }
}

class About extends React.Component {
    
    
  render() {
    
    
    return (
      <div>
        about
      </div>
    )
  }
}

class App extends React.Component {
    
    
  state = {
    
    
    msg: 'react-router-dom'
  }
  render() {
    
    
    let {
    
     msg } = this.state;
    return (
      <div className="wrap">
        <h2>{
    
    msg}</h2>
        <NavLink to="/home" activeClassName='active996'>home</NavLink>
        <NavLink to="/about" activeClassName='active996'>about</NavLink>
        {
    
    /* Switch的作用:提高路由的匹配效率,即一一对应,找到了就不要继续向下匹配了 */}
        <Switch>
          <Route path='/home' component={
    
    Home}></Route>
          <Route path='/about' component={
    
    About}></Route>
          <Route path='/about' component={
    
    Home}></Route>
        </Switch>
      </div>
    )
  }
}

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>, document.querySelector('#root'));

4.Redirect 的使用

  • 一般写在所有路由组件的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由
import React, {
    
     Component } from 'react'
import ReactDOM from 'react-dom';
import {
    
     BrowserRouter,Link, Route, NavLink, Switch, Redirect } from 'react-router-dom';
import './normalize.css';

class Home extends React.Component {
    
    
  render() {
    
    
    return (
      <div>
        home
      </div>
    )
  }
}

class About extends React.Component {
    
    
  render() {
    
    
    return (
      <div>
        about
      </div>
    )
  }
}

class App extends React.Component {
    
    
  state = {
    
    
    msg: 'react-router-dom'
  }
  render() {
    
    
    let {
    
     msg } = this.state;
    return (
      <div className="wrap">
        <h2>{
    
    msg}</h2>
        <NavLink to="/home" activeClassName='active996'>home</NavLink>
        <NavLink to="/about" activeClassName='active996'>about</NavLink>
        <Switch>
          <Route path='/home' component={
    
    Home}></Route>
          <Route path='/about' component={
    
    About}></Route>
          {
    
    /* 当所有路由都无法匹配时,跳转到Redirect指定的路由 */}
          <Redirect to='/about'></Redirect>
        </Switch>
      </div>
    )
  }
}

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>, document.querySelector('#root'));

5.push和replace(默认)属性的使用

import React, {
    
     Component } from 'react'
import ReactDOM from 'react-dom';
import {
    
     BrowserRouter,Link, Route, NavLink, Switch, Redirect } from 'react-router-dom';
import './normalize.css';

class Home extends React.Component {
    
    
  render() {
    
    
    return (
      <div>
        home
      </div>
    )
  }
}

class About extends React.Component {
    
    
  render() {
    
    
    return (
      <div>
        about
      </div>
    )
  }
}

class App extends React.Component {
    
    
  state = {
    
    
    msg: 'react-router-dom'
  }
  render() {
    
    
    let {
    
     msg } = this.state;
    return (
      <div className="wrap">
        <h2>{
    
    msg}</h2>
        {
    
    /* 配置了replace属性只会,单击链接将替换历史堆栈中的当前入口,而不是添加新入口 */}
        {
    
    /* 默认是push属性 */}
        <NavLink to="/home" replace activeClassName='active996'>home</NavLink>
        <NavLink to="/about" replace activeClassName='active996'>about</NavLink>
        <Switch>
          <Route path='/home' component={
    
    Home}></Route>
          <Route path='/about' component={
    
    About}></Route>
        </Switch>
      </div>
    )
  }
}

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>, document.querySelector('#root'));

6.路由的模糊匹配(默认)和严格匹配

  • 默认使用的是模糊匹配(简单记:[输入的路径]必须包含要[匹配的路径],且顺序要一致)
  • 开启严格匹配:<Route exact={true} path="/about" component={About}>
  • 严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由
import React, {
    
     Component } from 'react'
import ReactDOM from 'react-dom';
import {
    
     BrowserRouter,Link, Route, NavLink, Switch, Redirect } from 'react-router-dom';
import './normalize.css';

class Home extends React.Component {
    
    
  render() {
    
    
    return (
      <div>
        home
      </div>
    )
  }
}

class About extends React.Component {
    
    
  render() {
    
    
    return (
      <div>
        about
      </div>
    )
  }
}

class App extends React.Component {
    
    
  state = {
    
    
    msg: 'react-router-dom'
  }
  render() {
    
    
    let {
    
     msg } = this.state;
    return (
      <div className="wrap">
        <h2>{
    
    msg}</h2>
        <NavLink to="/home/1/1" activeClassName='active996'>home</NavLink>
        <NavLink to="/about/2" activeClassName='active996'>about</NavLink>
        <Switch>
          {
    
    /* 配置了exact属性,就代表输入路径(to)和匹配路径(path)要完全一致,否则匹配不了,但是一般不开,否则会发生一些意料之外的问题 */}
          <Route exact path='/home/1/1' component={
    
    Home}></Route>
          <Route path='/about' component={
    
    About}></Route>
          <Redirect to='/about'></Redirect>
        </Switch>
      </div>
    )
  }
}

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>, document.querySelector('#root'));

7.嵌套路由

  • 注册子路由时要写上父路由的path值
  • 路由的匹配时按照注册路由的顺序进行的
import React, {
    
     Component } from 'react'
import ReactDOM from 'react-dom';
import {
    
     BrowserRouter,Link, Route, NavLink, Switch, Redirect } from 'react-router-dom';
import './normalize.css';

class HomeDetails extends React.Component {
    
    
  state = {
    
    
    msg: '这里是home详情组件'
  }
  render() {
    
    
    let {
    
     msg } = this.state;
    return (
      <div className="home">
        <h4>{
    
    msg}</h4>
      </div>
    )
  }
}

class Home extends React.Component {
    
    
  state = {
    
    
    msg: '这里是home组件'
  }
  render() {
    
    
    let {
    
     msg } = this.state;
    return (
      <div className="home">
        <h3>{
    
    msg}</h3>
        <NavLink to='/home/details'>home详情</NavLink>
        <Switch>
          {
    
    /* 当路由匹配路径的时候,是会匹配所有NavLink中to属性的路径,由于NavLink的默认是模糊匹配,为了保持父路由组件还能存在到当前界面中所以要注册子路由时要写上父路由的path值 */}
          {
    
    /* 注意点:1.父路由组件不能开启exact属性,否则就不能匹配 */}
          {
    
    /* 注意点:2.如果不添加父路由组件会发生,路由匹配不上的问题,就会导致页面不能正常显示 */}
          <Route to='/home/details' component={
    
    HomeDetails}></Route>
        </Switch>
      </div>
    )
  }
}

class App extends React.Component {
    
    
  state = {
    
    
    msg: 'react-router-dom'
  }
  render() {
    
    
    let {
    
     msg } = this.state;
    return (
      <div className="wrap">
        <h2>{
    
    msg}</h2>
        <NavLink to='/home'>home</NavLink>
        <Switch>
          <Route path='/home' component={
    
    Home}></Route>
        </Switch>
      </div >
    )
  }
}

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>, document.querySelector('#root'));

8.向路由组件中传递参数

8.1向路由组件中传递params参数

import React, {
    
     Component } from 'react'
import ReactDOM from 'react-dom';
import {
    
     BrowserRouter,Link, Route, NavLink, Switch, Redirect } from 'react-router-dom';
import './normalize.css';

class Detial extends React.Component {
    
    
  state = {
    
    
    msg: '这里是详情组件'
  }
  render() {
    
    
    let {
    
     msg } = this.state;
    // 3.接受params参数
    let {
    
     props: {
    
     match: {
    
     params } } } = this;
    console.log(params);
    let infoArr = [];
    for (const [key, value] of Object.entries(params)) {
    
    
      infoArr.push(
        <p key={
    
    key}>{
    
    key}-{
    
    value}</p>
      )
    }
    return (
      <div className="detial">
        <h3>{
    
    msg}</h3>
        {
    
    infoArr}
      </div>
    )
  }
}

class App extends React.Component {
    
    
  state = {
    
    
    msg: 'react-router-dom',
    arr: [
      {
    
     name: '张三', id: 0 },
      {
    
     name: '李四', id: 1 },
      {
    
     name: '王五', id: 2 }
    ]
  }
  render() {
    
    
    let {
    
     msg, arr } = this.state;
    return (
      <div className="wrap">
        <h2>{
    
    msg}</h2>
        {
    
    
          arr.map(item => {
    
    
            return (
              // 1.向路由组件传递params参数
              <NavLink to={
    
    `/detial/${
      
      item.id}/${
      
      item.name}`} key={
    
    item.id} activeClassName='detialActive' > {
    
     item.name}</NavLink>
            )
          })
        }
        <Switch>
          {
    
    /* 2.接受params形式的参数 */}
          <Route path='/detial/:id/:name' component={
    
    Detial}></Route>
        </Switch>
      </div >
    )
  }
}

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>, document.querySelector('#root'));

8.2向路由组件中传递search参数

import React, {
    
     Component } from 'react'
import ReactDOM from 'react-dom';
import {
    
     BrowserRouter,Link, Route, NavLink, Switch, Redirect } from 'react-router-dom';
import './normalize.css';
import qs from 'querystring';

class Detial extends React.Component {
    
    
  state = {
    
    
    msg: '这里是详情组件'
  }
  render() {
    
    
    let {
    
     msg } = this.state;
    // 3.接受state参数
    let {
    
     props: {
    
     location: {
    
     search } } } = this;
    let parseStr = qs.parse(search.substring(1));
    let infoArr = [];
    for (const [key, value] of Object.entries(parseStr)) {
    
    
      infoArr.push(
        <p key={
    
    key}>{
    
    key}-{
    
    value}</p>
      )
    }
    return (
      <div className="detial">
        <h3>{
    
    msg}</h3>
        {
    
    infoArr}
      </div>
    )
  }
}

class App extends React.Component {
    
    
  state = {
    
    
    msg: 'react-router-dom',
    arr: [
      {
    
     name: '张三', id: 0 },
      {
    
     name: '李四', id: 1 },
      {
    
     name: '王五', id: 2 }
    ]
  }
  render() {
    
    
    let {
    
     msg, arr } = this.state;
    return (
      <div className="wrap">
        <h2>{
    
    msg}</h2>
        {
    
    
          arr.map(item => {
    
    
            return (
              // 1.向路由组件传递state参数
              <NavLink to={
    
    `/detial?id=${
      
      item.id}&name=${
      
      item.name}`} key={
    
    item.id} activeClassName='detialActive' > {
    
     item.name}</NavLink>
            )
          })
        }
        <Switch>
          {
    
    /* 2.接受state形式的参数------正常注册路由即可 */}
          <Route path='/detial' component={
    
    Detial}></Route>
        </Switch>
      </div >
    )
  }
}

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>, document.querySelector('#root'));

8.3向路由组件中传递state参数

import React, {
    
     Component } from 'react'
import ReactDOM from 'react-dom';
import {
    
     BrowserRouter,Link, Route, NavLink, Switch, Redirect } from 'react-router-dom';
import './normalize.css';

class Detial extends React.Component {
    
    
  state = {
    
    
    msg: '这里是详情组件'
  }
  render() {
    
    
    let {
    
     msg } = this.state;
    // 3.接受state参数
    let {
    
     props: {
    
     location: {
    
     state } } } = this;
    let infoArr = [];
    for (const [key, value] of Object.entries(state)) {
    
    
      infoArr.push(
        <p key={
    
    key}>{
    
    key}-{
    
    value}</p>
      )
    }
    return (
      <div className="detial">
        <h3>{
    
    msg}</h3>
        {
    
    infoArr}
      </div>
    )
  }
}

class App extends React.Component {
    
    
  state = {
    
    
    msg: 'react-router-dom',
    arr: [
      {
    
     name: '张三', id: 0 },
      {
    
     name: '李四', id: 1 },
      {
    
     name: '王五', id: 2 }
    ]
  }
  render() {
    
    
    let {
    
     msg, arr } = this.state;
    return (
      <div className="wrap">
        <h2>{
    
    msg}</h2>
        {
    
    
          arr.map(item => {
    
    
            return (
              // 1.向路由组件传递state参数
              <NavLink to={
    
    {
    
    
                pathname: '/detial',
                state: {
    
    
                  id: item.id,
                  name: item.name
                }
              }} key={
    
    item.id} activeClassName='detialActive' > {
    
     item.name}</NavLink>
            )
          })
        }
        <Switch>
          {
    
    /* 2.接受state形式的参数------正常注册路由即可 */}
          <Route path='/detial' component={
    
    Detial}></Route>
        </Switch>
      </div >
    )
  }
}

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>, document.querySelector('#root'));

9.编程式导航

  • 借助this.props.history对象上的API对操作路由跳转/前进/后退
  • this.props.history.push()
  • this.props.history.replace()
  • this.props.history.goBack()
  • this.props.history.goForward()
  • this.props.history.go()
import React from 'react';
import './index.scss';
import {
    
     Link, Route, NavLink, Switch, Redirect, withRouter } from 'react-router-dom';
import qs from 'querystring';

class Home extends React.Component {
    
    
  state = {
    
    
    msg: '这里是home组件'
  }
  render() {
    
    
    let {
    
     props: {
    
     location: {
    
     search, state }, match: {
    
     params } } } = this;
    if (!!state) {
    
    
      console.log('state', state);
    } else if (Object.keys(search).length > 0) {
    
    
      console.log('search', qs.parse(search.substring(1)));
    } else if (Object.keys(params).length > 0) {
    
    
      console.log('params', params);
    } else {
    
    
      console.log('没有参数');
    }
    let {
    
     msg } = this.state;
    return (
      <div className="home">
        <h3>{
    
    msg}</h3>
      </div>
    )
  }
}

class App extends React.Component {
    
    
  state = {
    
    
    msg: 'react-router-dom',
    routeHTML: null,
    obj: {
    
     name: '张三', age: 18 }
  }
  goForward = () => {
    
    
    let {
    
     props: {
    
     history } } = this;
    history.goForward();
  }
  goBack = () => {
    
    
    let {
    
     props: {
    
     history } } = this;
    history.goBack();
  }
  go = (n) => {
    
    
    let {
    
     props: {
    
     history } } = this;
    history.go(n);
  }
  jumpHomeTypePush = (str, event) => {
    
    
    let {
    
     obj, routeHTML } = this.state;
    let {
    
     props: {
    
     history } } = this;
    // 如果是history.replace只是替换路由,不添加
    switch (str) {
    
    
      case 'no':
        routeHTML = (<Route path="/home" component={
    
    Home}></Route>);
        history.push(`/home`);
        break;
      case 'params':
        routeHTML = (<Route path="/home/:name/:age" component={
    
    Home}></Route>);
        history.push(`/home/${
      
      obj.name}/${
      
      obj.age}`);
        break;
      case 'search':
        routeHTML = (<Route path="/home" component={
    
    Home}></Route>);
        history.push(`/home?name=${
      
      obj.name}&age=${
      
      obj.age}`);
        break;
      case 'state':
        routeHTML = (<Route path="/home" component={
    
    Home}></Route>);
        history.push('/home', {
    
    
          name: obj.name,
          age: obj.age
        });
        break;
    };
    this.setState({
    
    
      routeHTML
    });
  }
  render() {
    
    
    let {
    
     msg, routeHTML } = this.state;
    return (
      <div className="wrap">
        <h2>{
    
    msg}
          <button onClick={
    
    this.goBack}>后退</button>
          <button onClick={
    
    this.goForward}>前进</button>
          <button onClick={
    
    () => {
    
    
            this.go(-2)
          }}>n(n>0前进n/n<0后退n)</button></h2>
        <button onClick={
    
    
          (event) => {
    
    
            this.jumpHomeTypePush('no', event)
          }
        }>跳转到home组件-push方式</button>
        <button onClick={
    
    
          (event) => {
    
    
            this.jumpHomeTypePush('params', event)
          }
        }>跳转到home组件-push方式-params参数传参</button>
        <button onClick={
    
    
          (event) => {
    
    
            this.jumpHomeTypePush('search', event)
          }
        }>跳转到home组件-push方式-search参数传参</button>
        <button onClick={
    
    
          (event) => {
    
    
            this.jumpHomeTypePush('state', event)
          }
        }>跳转到home组件-push方式-state参数传参</button>
        <hr />

        {
    
    
          routeHTML
        }
      </div >
    )
  }
}
//withRouter可以加工一个一般组件,让一般组件具备路由组件所特有的API;
//withRouter的返回值是一个新组件
let WithRouterApp = withRouter(App);

ReactDOM.render(
  <BrowserRouter>
    <WithRouterApp />
  </BrowserRouter>, document.querySelector('#root'));

10.BrowserRouter和HashRouter的区别

  • 底层原理不一样
    • BrowserRouter使用的是H5的history API,不兼容IE9以下版本
    • HashRouter使用的是URL的哈希值
  • path的表现形式不一样
    • BrowserRouter的路径中没有#,例如:localhost:3000/demo/test
    • HashRouter的路径中包含#,例如:localhost:3000/#/demo/test
  • 刷新后对路由的state参数的影响
    • BrowserRouter没有任何影响,因为state保存在history对象中
    • HashRouter刷新后会导致路由state参数丢失
  • 备注: HashRouter可以用于解决一些路径错误相关的问题

猜你喜欢

转载自blog.csdn.net/big_sun_962464/article/details/113061403