06-React的路由

news2024/11/29 8:01:48

06-React的路由


1.相关理解

1).SPA的理解

  1. 单页Web应用(single page web application,SPA)。
  2. 整个应用只有一个完整的页面。
  3. 点击页面中的链接不会刷新页面,只会做页面的局部更新。
  4. 数据都需要通过ajax请求获取, 并在前端异步展现。

2).路由的理解

a.什么是路由?
  1. 一个路由就是一个映射关系(key:value)
  2. key为路径, value可能是functioncomponent
b.路由分类
①.后端路由:
  1. 理解: valuefunction, 用来处理客户端提交的请求。

  2. 注册路由:

     router.get(path, function(req, res))
    
  3. 工作过程:当node接收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据

②.前端路由:
  1. 浏览器端路由,valuecomponent,用于展示页面内容。

  2. 注册路由:

    <Route path="/test" component={Test}>
    
  3. 工作过程:当浏览器的path变为/test时, 当前路由组件就会变为Test组件

3).react-router-dom的理解

  1. react的一个插件库。
  2. 专门用来实现一个SPA应用。
  3. 基于react的项目基本都会用到此库。

2. react基本路由使用

需求:

1).实现:

a.BrowserRouter,Link,Route三个API的基本使用
  1. 完成组件的静态结构,明确好界面中的导航区、展示区

    //App.jsx
    export default class App extends Component {
        render() {
            return (
                <div>
                    <div className="row">
                        <div className="col-xs-offset-2 col-xs-8">
                            <Header/>
                        </div>
                    </div>
                    <div className="row">
                        <div className="col-xs-2 col-xs-offset-2">
                            <div className="list-group">
                                {/* 原生html中,靠<a>跳转不同的页面 */}
                                <a className="list-group-item active" href="./about.html">About</a>
                                <a className="list-group-item" href="./home.html">Home</a> 
                            </div>
                        </div>
                        <div className="col-xs-6">
                            <div className="panel">
                                <div className="panel-body">
                                    <About/>
                                    <Home/>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            )
        }
    }
    
    //Header.jsx
    export default class Header extends Component {
      render() {
        return (
            <div className="page-header"><h2>React Router Demo</h2></div>
        )
      }
    }
    
    //About.jsx
    export default class About extends Component {
      render() {
        return (
            <h3>我是About的内容</h3>
        )
      }
    }
    
    //Home.jsx
    export default class Home extends Component {
      render() {
        return (
          <h3>我是Home的内容</h3>
        )
      }
    }
    
  2. 引入并使用路由API注册路由

    导航区的a标签改为Link标签

    <Link to="/xxxxx">Demo</Link>
    

    展示区写Route标签进行路径的匹配

    <Route path='/xxxx'component={Demo}/>
    
    import { Link, BrowserRouter, Route } from 'react-router-dom'
    
    export default class App extends Component {
      render() {
        return (
          <div>
            <div className="row">
              <div className="col-xs-offset-2 col-xs-8">
                <Header/>
              </div>
            </div>
            <div className="row">
              <div className="col-xs-2 col-xs-offset-2">
                <div className="list-group">
                  {/* 原生html中,靠<a>跳转不同的页面 */}
                  {/* <a className="list-group-item active" href="./about.html">About</a>
                  <a className="list-group-item" href="./home.html">Home</a> */}
                  {/* 在React中靠路由链接实现切换组件--编写路由链接 */}
                  {/* <BrowserRouter> */}
                    <Link className="list-group-item" to="/about">About</Link>
                    <Link className="list-group-item" to="/home">Home</Link>
                  {/* </BrowserRouter> */}
                </div>
              </div>
              <div className="col-xs-6">
                <div className="panel">
                  <div className="panel-body">
                    {/* 注册路由 */}
                    {/* <BrowserRouter> */}
                      <Route path="/about" component={About} />
                      <Route path="/home" component={Home} />
                    {/* </BrowserRouter> */}
                  </div>
                </div>
              </div>
            </div>
          </div>
        )
      }
    }
    

    注意点:

    是两种路由模式中的一种,需要将路由链接和注册路由的标签写在同一个标签中产生关联,为了简化后期编码的便利,一般都是直接用标签将父组件包裹起来,这样整个应用中子组件都可以产生路由关联

    import {BrowserRouter} from 'react-router-dom'
    createRoot(document.getElementById('root')).render(<BrowserRouter><App/></BrowserRouter>)
    
b.路由组件与一般组件

将案例说,Header组件为一般组件,AboutHome组件为路由组件,所以可以将AboutHome组件放在一个名为pages文件夹中,这个文件夹专门用来存放路由组件文件,components文件夹用来存放一般组件的文件

路由组件与一般组件的区别:

1.写法不同:
一般组件:

<Demo/>

​ 路由组件:

<Route path:="/demo"component={Demo}/>

2.存放位置不同:
一般组件:components
路由组件:pages
3.接收到的props不同:
一般组件:写组件标签时传递了什么,就能收到什么
路由组件:接收到三个固定的属性:

history:
          go:f go(n)
          goBack:f goBack()
          goForward:f goForward()
          push:f push(path,state)
          replace:f replace(path,state)
location:
          pathname:"/about"
          search:"
          state:undefined 
match:
          params:{}
          path:"/about"
          url:"/about"
//About.jsx
export default class About extends Component {
  render() {
    console.log('About路由组件:',this.props);
    return (
        <h3>我是About的内容</h3>
    )
  }
}

c.NavLink与封装NavLink

需求:当点击某个组件链接时,该链接会高亮。

实现:

  1. 原生JS:通过链接元素的点击事件将高亮样式active加到该链接元素上
  2. CSS:通过元素的:hover伪类选择器为元素添加高亮效果
  3. Vue:通过@click事件通过判断条件将高亮样式active加到该链接元素上
  4. React:通过NavLink标签实现,且该标签的默认高亮样式名就为active
<!-- index.html -->
<head>
    <meta charset="UTF-8">
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="./css/bootstrap.css">
    <style>
        .atguigu{
            background-color: rgb(209, 137, 4) !important;
            color: white !important;
        }
    </style>
    <title>08</title>
</head>
<body>
    <div id="root"></div>
</body>
</html>
//App.jsx
export default class App extends Component {
  render() {
    return (
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <Header/>
          </div>
        </div>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
              {/* NavLink可以实现路由链接的高亮通过activeClassName指定样式名 */}
                <NavLink activeClassName="atguigu" className="list-group-item" to="/about">About</NavLink>
                <NavLink activeClassName="atguigu" className="list-group-item" to="/home">Home</NavLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                  <Route path="/about" component={About} />
                  <Route path="/home" component={Home} />
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}
封装NavLink

可以通过封装NavLink的方式来减少几个NavLink标签实际应用时重复相同的内容

//MyNacLink.jsx
import { NavLink } from 'react-router-dom'
export default class MyNacLink extends Component {
    render() {
        const {to,title}=this.prosp  
        return (
            <NavLink activeClassName="atguigu" className="list-group-item" to={to}>{title}</NavLink>
        )
    }
}
export default class App extends Component {
    render() {
        return (
            <div>
                <div className="row">
                    <div className="col-xs-offset-2 col-xs-8">
                        <Header/>
                    </div>
                </div>
                <div className="row">
                    <div className="col-xs-2 col-xs-offset-2">
                        <div className="list-group">
                            <MyNacLink to="/about" title="About"/>
                            <MyNacLink to="/home" title="Home"/> 
                        </div>
                    </div>
                    <div className="col-xs-6">
                        <div className="panel">
                            <div className="panel-body">
                                <Route path="/about" component={About} />
                                <Route path="/home" component={Home} />
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}

不足之处在于假如在MyNacLink组件中传递了太多的数值,那么MyNacLink组件取值将会变得繁琐,比如

<MyNacLink to="/about" title="About" a="1" b="2"/>
  1. 通过解构赋值的方式将数值从this.props中取很繁琐:
  2. title值需要另外通过{}
export default class MyNacLink extends Component {
  render() {
    const {to,title,a,b}=this.props
    return (
        <NavLink activeClassName="atguigu" className="list-group-item" to={to} a={a} b={b}>{title}</NavLink>
    )
  }
}

假如将title值写在标签体中,这样就可以通过this.props.children可以获取标签体内容:

//标签体内容是一个特殊的标签属性 
<MyNacLink to="/about" a="1" b="2">About</MyNacLink>
export default class MyNacLink extends Component {
  render() {
    console.log(this.props);
    // const {to,title}=this.props
    return (
        <NavLink activeClassName="atguigu" className="list-group-item" to={to}>{title}</NavLink>
    )
  }
}

这样就可以通过...运算符将直接将this.props中所有的值都传递到NavLink组件中:

export default class MyNacLink extends Component {
  render() {
    return (
        <NavLink activeClassName="atguigu" className="list-group-item" {...this.props}>{title}</NavLink>
    )
  }
}
d.Switch的使用

通常情况下,pathcomponent是一一对应的关系,但是不免有时候会重复path,这样会造成同时显示两个组件的内容:

export default class App extends Component {
  render() {
    return (
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <Header />
          </div>
        </div>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
              <MyNacLink to="/about" a="1" b="2">About</MyNacLink>
              <MyNacLink to="/home">Home</MyNacLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                  <Route path="/about" component={About} />
                  <Route path="/home" component={Home} />
                  <Route path="/home" component={Text} />
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

可以使用Switch来解决这个问题,Switch可以提高路由匹配效率(单一匹配)。

export default class App extends Component {
    render() {
        return (
            <div>
                <div className="row">
                    <div className="col-xs-offset-2 col-xs-8">
                        <Header />
                    </div>
                </div>
                <div className="row">
                    <div className="col-xs-2 col-xs-offset-2">
                        <div className="list-group">
                            <MyNacLink to="/about" a="1" b="2">About</MyNacLink>
                            <MyNacLink to="/home">Home</MyNacLink>
                        </div>
                    </div>
                    <div className="col-xs-6">
                        <div className="panel">
                            <div className="panel-body">
                                <Switch>
                                    <Route path="/about" component={About} />
                                    <Route path="/home" component={Home} />
                                    <Route path="/home" component={Text} />
                                </Switch>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}
e.解决多级路径刷新页面样式丢失的问题

假如在路由匹配路径为多重,那么当网页刷新时就会出现样式丢失的问题:

export default class App extends Component {
    render() {
        return (
            <div>
                <div className="row">
                    <div className="col-xs-offset-2 col-xs-8">
                        <Header />
                    </div>
                </div>
                <div className="row">
                    <div className="col-xs-2 col-xs-offset-2">
                        <div className="list-group">
                            <MyNacLink to="/atguigu/about" a="1" b="2">About</MyNacLink>
                            <MyNacLink to="/atguigu/home">Home</MyNacLink>
                        </div>
                    </div>
                    <div className="col-xs-6">
                        <div className="panel">
                            <div className="panel-body">
                                <Switch>
                                    <Route path="/atguigu/about" component={About} />
                                    <Route path="/atguigu/home" component={Home} />
                                </Switch>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}

问题:为什么会造成样式的丢失呢?

回答:在刷新后,请求的bootstrap.css的响应内容发现了变化:

刷新前请求的bootstrap.css的响应内容为一段CSS样式代码:

刷新后请求的bootstrap.css的响应内容为一段HTML代码,而且返回的HTML网页内容就是当前react脚手架项目的index.html文件的内容:

**分析原因:**刷新前后请求bootstrap.css的路径不一样

  • 刷新前的路径:

  • 刷新后的路径:

    可以看到脚手架在请求bootstrap.css资源时,错误的将/atguigu也当成了请求路径的一部分,因此导致请求不到正确的样式资源。

    在脚手架中有一个配置,当脚手架请求不到正确内容时,会将根目录public下的index.html文件返回作为响应

解决方案:

  1. 将引入样式文件的相对路径进行修改

    <link rel="stylesheet" href="/css/bootstrap.css">
    
  2. 在引入样式文件的路径中添加%PUBLIC_URL%

    <link rel="stylesheet" href="%PUBLIC_URL%/css/bootstrap.css">
    
  3. 将路由模式修改为HashRouter

    import { HashRouter } from "react-router-dom";
    createRoot(document.getElementById('root')).render(<HashRouter><App/></HashRouter>)
    
f.路由的严格匹配与模糊匹配

在路由匹配中有严格匹配与模糊匹配两种模式,默认是模糊模式,因此可以在路由匹配正确路径后面添加其他内容:

export default class App extends Component {
  render() {
    return (
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <Header />
          </div>
        </div>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
              <MyNacLink to="/about" a="1" b="2">About</MyNacLink>
              <MyNacLink to="/home/a/b">Home</MyNacLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                <Switch>
                  <Route exact path="/about" component={About} />
                  <Route exact path="/home" component={Home} />
                </Switch>
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

需要注意:模糊匹配只会匹配路径的第一个路径字段,如果第一个匹配不上也不会往后匹配了

export default class App extends Component {
  render() {
    return (
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <Header />
          </div>
        </div>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
              <MyNacLink to="/about" a="1" b="2">About</MyNacLink>
              <MyNacLink to="/a/home/b">Home</MyNacLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                <Switch>
                  <Route path="/about" component={About} />
                  <Route path="/home" component={Home} />
                </Switch>
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

开启严格模式:
<Route exact={true}path="/about"component={About}
export default class App extends Component {
  render() {
    return (
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <Header />
          </div>
        </div>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
              <MyNacLink to="/about" a="1" b="2">About</MyNacLink>
              <MyNacLink to="/home/a/b">Home</MyNacLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                <Switch>
                  <Route exact path="/about" component={About} />
                  <Route exact path="/home" component={Home} />
                </Switch>
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}
  1. 默认使用的是模糊匹配(简单记:【输入的路径】必须包含要【匹配的路径】,且顺序要一致)
  2. 开启严格匹配:<Route exact={true}path="/about"component={About}/>
  3. 严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由
g.Redirect重定向

当需要组件一加载就显示某个路由组件时,可以使用Redirect重定向到指定的路由组件

export default class App extends Component {
  render() {
    return (
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <Header />
          </div>
        </div>
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
              <MyNacLink to="/about">About</MyNacLink>
              <MyNacLink to="/home">Home</MyNacLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                <Switch>
                  <Route path="/about" component={About} />
                  <Route path="/home" component={Home} />
                  <Redirect to="/home"/>
                </Switch>
              </div>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

3.路由传递参数

1).嵌套路由

需求:

实现:

  1. 注册子路由时要写上父路由的path值
  2. 路由的匹配是按照注册路由的顺序进行的
//Home.js
export default class Home extends Component {
  render() {
    return (
      <div>
        <h2>Home组件内容</h2>
        <div>
          <ul className="nav nav-tabs">
            <li>
              <MyNavLink to="/home/news">News</MyNavLink>
            </li>
            <li>
              <MyNavLink to="/home/message">Message</MyNavLink>
            </li>
          </ul>
          <Switch>
            <Route path="/home/news" component={News} />
            <Route path="/home/message" component={Message} />
            <Redirect to="/home/news"/>
          </Switch>
        </div>
      </div>
    )
  }
}

2).向路由组件传递参数

需求:

a.向路由传递params参数
  1. 路由链接(携带参数):

    <Link to='/demo/test/tom/18'}>详情</Link>
    
  2. 注册路由(声明接收):

    <Route path="/demo/test/:name/:age"component={Test}/>
    
    export default class Message extends Component {
        state = {
            messageArr: [
                { id: '001', title: '消息1' },
                { id: '002', title: '消息2' },
                { id: '003', title: '消息3' },
            ]
        }
        render() {
            const { messageArr } = this.state
            return (
                <div>
                    <ul>
                        {
                            messageArr.map(msgObj => {
                                return (
                                    <li key={msgObj.id}>
                                        {/* 向路由组件传递params参数 */}
                                        <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp;
                                    </li>
                                )
                            })
                        }
                    </ul>
                    <hr />
                    <Route path="/home/message/detail/:id/:title" component={Detail}/>
                </div>
            )
        }
    }
    
  3. 接收参数:

    const{id,title}=this.props.match.params 
    
    const DetailData = [
        { id: '001', content: "你好,中国" },
        { id: '002', content: "你好,比奇堡" },
        { id: "003", content: "你好,海绵宝宝" }
    ]
    export default class Detail extends Component {
        render() {
            // 接收params参数
            console.log(this.props);
            const { id, title } = this.props.match.params
            const findResult = DetailData.find((detailObj) => {
                return detailObj.id === id
            })
            return (
                <ul>
                    <li>ID:{id}</li>
                    <li>TITLE:{title}</li>
                    <li>CONTENT:{findResult.content}</li>
                </ul>
            )
        }
    }
    

b.向路由传递search参数
  1. 路由链接(携带参数):

    <Link to='/demo/test?name:=tom&age=18'}>详情</Link>
    
  2. 注册路由(无需声明,正常注册即可):

    <Route path="/demo/test"component={Test}/>
    
    export default class Message extends Component {
        state = {
            messageArr: [
                { id: '001', title: '消息1' },
                { id: '002', title: '消息2' },
                { id: '003', title: '消息3' },
            ]
        }
        render() {
            const { messageArr } = this.state
            return (
                <div>
                    <ul>
                        {
                            messageArr.map(msgObj => {
                                return (
                                    <li key={msgObj.id}>
                                        {/* 向路由组件传递search参数 */}
                      <Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp;
                                    </li>
                                )
                            })
                        }
                    </ul>
                    <hr />
                    {/* <Route path="/home/message/detail/:id/:title" component={Detail}/> */}
                    {/* search参数无需声明接收,正常注册路由即可 */}
                    <Route path="/home/message/detail" component={Detail}/>
                </div>
            )
        }
    }
    
  3. 接收参数:

    const{search}=this.props.location
    
  4. 备注:获取到的searchurlencoded编码字符串,需要借助querystring解析

    import qs from "query-string"
    console.log(qs.stringify({name:"tom",age:18}));
    

    urlencoded编码方式:
    let obj={name:"tom",age:18} => name=tom&age=18 key=value&key=value

    const DetailData = [
        { id: '001', content: "你好,中国" },
        { id: '002', content: "你好,比奇堡" },
        { id: "003", content: "你好,海绵宝宝" }
    ]
    export default class Detail extends Component {
        render() {
            // 接收search参数
            console.log(this.props);
            const {search}=this.props.location
         	//   search.slice(1):去掉字符串前的?
            const {id,title}=qs.parse(search.slice(1))
            const findResult = DetailData.find((detailObj) => {
                return detailObj.id === id
            })
            return (
                <ul>
                    <li>ID:{id}</li>
                    <li>TITLE:{title}</li>
                    <li>CONTENT:{findResult.content}</li>
                </ul>
            )
        }
    }
    

c.向路由传递state参数
  1. 路由链接(携带参数):

    <Link to={{path:'/demo/test',state:{name:'tom',age:18})}>详情</Link>
    
  2. 注册路由(无需声明,正常注册即可):

    <Route path:="/demo/test" component={Test}/>
    
    export default class Message extends Component {
        state = {
            messageArr: [
                { id: '001', title: '消息1' },
                { id: '002', title: '消息2' },
                { id: '003', title: '消息3' },
            ]
        }
        render() {
            const { messageArr } = this.state
            return (
                <div>
                    <ul>
                        {
                            messageArr.map(msgObj => {
                                return (
                                    <li key={msgObj.id}>
                                        {/* 向路由组件传递state参数 */}
                              <Link to={{pathname:'/home/message/detail',state:{id:msgObj.id,title:msgObj.title}}}>{msgObj.title}</Link>
                                    </li>
                                )
                            })
                        }
                    </ul>
                    <hr />
                    {/* state参数无需声明接收,正常注册路由即可 */}
                    <Route path="/home/message/detail" component={Detail}/>
                </div>
            )
        }
    }
    
  3. 接收参数:this,props.location.state

    const DetailData = [
        { id: '001', content: "你好,中国" },
        { id: '002', content: "你好,比奇堡" },
        { id: "003", content: "你好,海绵宝宝" }
    ]
    export default class Detail extends Component {
        render() {
            // 接收state参数
         	// 切记需要添加 ||{} 以免引起报错   
            const {id,title}=this.props.location.state||{}
            const findResult = DetailData.find((detailObj) => {
                return detailObj.id === id
            })||{}
            return (
                <ul>
                    <li>ID:{id}</li>
                    <li>TITLE:{title}</li>
                    <li>CONTENT:{findResult.content}</li>
                </ul>
            )
        }
    }
    
  4. 备注:刷新也可以保留住参数

3).push模式和replace模式

  1. push模式相当于history模式,是在浏览器上一条浏览记录添加覆盖一条新的浏览记录
  2. replace模式相当于hash模式,是将浏览器上一条替换成新的浏览记录

在注册路由时开启replace模式:

<Route replace={true} path="/home/message/detail" component={Detail}/>

4.编程式路由导航

当需要在事件中进行跳转路由时,就可以使用编程式路由。

我们知道在路由组件的props中包含有historylocationmatch,其中history中的gogoBackgoForwardpushreplace三个方法就可以供我们实现编程式路由导航

a.基本使用
export default class Message extends Component {
    state = {
        messageArr: [
            { id: '001', title: '消息1' },
            { id: '002', title: '消息2' },
            { id: '003', title: '消息3' },
        ]
    }
    replaceShow = (id, title) => {
        this.props.history.replace(`/home/message/detail`)
    }
    pushShow = () => {
        this.props.history.push(`/home/message/detail`)
    }
    back=()=>{
        this.props.history.goBack()
    }
    forward=()=>{
        this.props.history.goForward()
    }
    render() {
        console.log(this.props);
        const { messageArr } = this.state
        return (
            <div>
                <ul>
                    {
                        messageArr.map(msgObj => {
                            return (
                                <li key={msgObj.id}>
                     <Link to={{ pathname: '/home/message/detail', state: { id: msgObj.id, title: msgObj.title } }}>{msgObj.title}</Link>
                                    &nbsp;<button onClick={() => this.pushShow()}>push查看</button>
                                    &nbsp;<button onClick={() => this.replaceShow()}>replace查看</button>
                                </li>
                            )
                        })
                    }
                </ul>
                <hr />
                <Route path="/home/message/detail" component={Detail} />
                <button onClick={this.back}>回退</button>
                <button onClick={this.forward}>前进</button>
            </div>
        )
    }
}

b.路由跳转+传递参数
①.传递param参数
export default class Message extends Component {
    state = {
        messageArr: [
            { id: '001', title: '消息1' },
            { id: '002', title: '消息2' },
            { id: '003', title: '消息3' },
        ]
    }
    replaceShow = (id, title) => {
        // replace跳转+传递param参数
       this.props.history.replace(`/home/message/detail/${id}/${title}`)
    }
    pushShow = (id, title) => {
        // push跳转+传递param参数
        this.props.history.push(`/home/message/detail/${id}/${title}`)
    }
    back=()=>{
        this.props.history.goBack()
    }
    forward=()=>{
        this.props.history.goForward()
    }
    render() {
        console.log(this.props);
        const { messageArr } = this.state
        return (
            <div>
                <ul>
                    {
                        messageArr.map(msgObj => {
                            return (
                                <li key={msgObj.id}>
                                    {/* 向路由组件传递params参数 */}
                                    {<Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp;
                                    &nbsp;<button onClick={()=>this.pushShow(msgObj.id,msgObj.title)}>push查看</button>
                                    &nbsp;<button onClick={()=>this.replaceShow(msgObj.id,msgObj.title)}>replace查看</button> 
                                </li>
                            )
                        })
                    }
                </ul>
                <hr />
                <Route path="/home/message/detail/:id/:title" component={Detail}/> 
                <button onClick={this.back}>回退</button>
                <button onClick={this.forward}>前进</button>
            </div>
        )
    }
}
②.传递query参数
export default class Message extends Component {
    state = {
        messageArr: [
            { id: '001', title: '消息1' },
            { id: '002', title: '消息2' },
            { id: '003', title: '消息3' },
        ]
    }
    replaceShow = (id, title) => {
        // replace跳转+传递query参数
        this.props.history.replace(`/home/message/detail?id=${id}&title=${title}`)
    }
    pushShow = (id, title) => {
        // push跳转+传递query参数
        this.props.history.push(`/home/message/detail?id=${id}&title=${title}`)
    }
    back=()=>{
        this.props.history.goBack()
    }
    forward=()=>{
        this.props.history.goForward()
    }
    render() {
        console.log(this.props);
        const { messageArr } = this.state
        return (
            <div>
                <ul>
                    {
                        messageArr.map(msgObj => {
                            return (
                                <li key={msgObj.id}>
                                    {/* 向路由组件传递search参数 */}
                              <Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp;
                                    &nbsp;<button onClick={()=>this.pushShow(msgObj.id,msgObj.title)}>push查看</button>
                                    &nbsp;<button onClick={()=>this.replaceShow(msgObj.id,msgObj.title)}>replace查看</button> 
                                </li>
                            )
                        })
                    }
                </ul>
                <hr />
                <Route path="/home/message/detail" component={Detail}/> 
                <button onClick={this.back}>回退</button>
                <button onClick={this.forward}>前进</button>
            </div>
        )
    }
}
③.传递state参数
export default class Message extends Component {
    state = {
        messageArr: [
            { id: '001', title: '消息1' },
            { id: '002', title: '消息2' },
            { id: '003', title: '消息3' },
        ]
    }
    replaceShow = (id, title) => {
        // replace跳转+传递state参数
        this.props.history.replace(`/home/message/detail`, { id, title })
    }
    pushShow = (id, title) => {
        // push跳转+传递state参数
        this.props.history.push(`/home/message/detail`, { id, title })
    }
    back=()=>{
        this.props.history.goBack()
    }
    forward=()=>{
        this.props.history.goForward()
    }
    render() {
        console.log(this.props);
        const { messageArr } = this.state
        return (
            <div>
                <ul>
                    {
                        messageArr.map(msgObj => {
                            return (
                                <li key={msgObj.id}>
                                    {/* 向路由组件传递state参数 */}
                     <Link to={{ pathname: '/home/message/detail', state: { id: msgObj.id, title: msgObj.title } }}>{msgObj.title}</Link>
                                    &nbsp;<button onClick={() => this.pushShow(msgObj.id, msgObj.title)}>push查看</button>
                                    &nbsp;<button onClick={() => this.replaceShow(msgObj.id, msgObj.title)}>replace查看</button>
                                </li>
                            )
                        })
                    }
                </ul>
                <hr />
                <Route path="/home/message/detail" component={Detail} />
                <button onClick={this.back}>回退</button>
                <button onClick={this.forward}>前进</button>
            </div>
        )
    }
}
c.withRouter

如果需要使一般路由也有跟路由组件一样的props属性以此来实现一些效果,比如浏览记录的回退和前进,可以使用withRouter让一般组件具备路由组件所特有的API

//Header.jsx
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'

class Header extends Component {
  back = () => {
    this.props.history.goBack()
  }
  forward = () => {
    this.props.history.goForward()
  }
  render() {
    return (
      <div className="page-header">
        <h2>React Router Demo</h2>
        &nbsp;<button onClick={this.back}>后退</button>
        &nbsp;<button onClick={this.forward}>前进</button>
      </div>
    )
  }
}
export default withRouter(Header)
  1. withRouter可以加工一般组件,让一般组件具备路由组件所特有的API
  2. withRouter的返回值是一个新组件

5.BrowserRouter与HashRouter的区别

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1096173.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2018-2019 ACM-ICPC, Asia Nanjing Regional Contest G. Pyramid(组合数学 计数)

题目 t(t<1e6)组样例&#xff0c;每次给定一个n(n<1e9)&#xff0c;统计边长为n的上述三角形的等边三角形个数 其中等边三角形的三个顶点&#xff0c;可以在所有黑色三角形&白色三角形的顶点中任取&#xff0c; 答案对1e97取模 思路来源 申老师 & oeis A0003…

第 367 场 LeetCode 周赛题解

A 找出满足差值条件的下标 I 模拟 class Solution { public:vector<int> findIndices(vector<int> &nums, int indexDifference, int valueDifference) {int n nums.size();for (int i 0; i < n; i)for (int j 0; j < i; j)if (i - j > indexDiffe…

【探索Linux】—— 强大的命令行工具 P.11(基础IO,文件操作)

阅读导航 前言一、C语言的文件操作二、C的文件操作三、Linux系统文件操作&#xff08;I/O接口&#xff09;1. open()⭕传入多个打开方式&#xff08;按位或操作将不同的标志位组合在一起&#xff09; 2. write()3. read()4. close()5. lseek() 温馨提示 前言 前面我们讲了C语言…

vue3后台管理框架之axios二次封装

在开发项目的时候避免不了与后端进行交互,因此我们需要使用axios插件实现发送网络请求。在开发项目的时候 我们经常会把axios进行二次封装。 目的: 1:使用请求拦截器,可以在请求拦截器中处理一些业务(开始进度条、请求头携带公共参数) 2:使用响应拦截器,可以在响应拦截器…

Hadoop3教程(十二):MapReduce中Shuffle机制的概述

文章目录 &#xff08;95&#xff09; Shuffle机制什么是shuffle&#xff1f;Map阶段Reduce阶段 参考文献 &#xff08;95&#xff09; Shuffle机制 面试的重点 什么是shuffle&#xff1f; Map方法之后&#xff0c;Reduce方法之前的这段数据处理过程&#xff0c;就叫做shuff…

华为ICT——云计算基础知识、计算类技术听课笔记

ICT(information and communications technology):信息与通信技术 传统IT架构缺点 TCO&#xff1a;总体拥有成本 云计算模式 云计算价值 云计算通用点 虚拟化技术&#xff1a;将单台物理服务器虚拟为多台虚拟机使用&#xff0c;多台虚拟机共享物理服务器硬件资源。 虚拟化本质…

使用PM2部署spring-boot项目

一、打包应用 1、先清理之前的 2、修改pom.xml文件关于项目名称版本及jdk版本 3、在idea中直接打包项目 4、等打包完成后会在target文件夹下有一个xx.jar的文件,拷贝出来放到一个文件夹下&#xff0c;或者服务器指定目录下 二、使用pm2部署.jar文件 1、pm2的安装,参考地…

Linux性能优化--性能工具:特定进程CPU

4.0 概述 在用系统级性能工具找出是哪个进程降低了系统速度之后&#xff0c;你需要用特定进程性能工具来发现这个进程的行为。对此&#xff0c;Linux提供了丰富的工具用于追踪一个进程和应用程序性能的重要统计信息。 阅读本章后&#xff0c;你将能够&#xff1a; 确定应用程…

nodejs+vue水浒鉴赏平台系统

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

unity脚本的生命周期

方法名称调用时间Awake最早调用&#xff0c;所以一般可以在此实现单例模式OnEnable组件激活后调用&#xff0c;在Awake后会调用一次Start在Update之前调用一次&#xff0c;在OnEnable之后调用&#xff0c;可以在此设置一些初始值FixedUpdate固定频率调用方法&#xff0c;每次调…

多模态大模型NextGPT整体结构图、模型示意图和使用模型时示意图

NextGPT模型整体结构 项目地址 论文地址 模型示意图 使用模型时示意图

彩虹易支付 9.27 最新版加订单查询 sy 更新版

彩虹易支付 9.27 最新版加订单查询 sy 更新版 修复客服 2023/09/25&#xff1a; 1. 新增支付宝红包支付插件 2. 新增支付宝 APP 支付转 H5 支付 3. 更新了几个支付插件 安装教程&#xff1a; 环境&#xff1a;php7.2 上传后访问域名进行安装即可 源码下载&#xff1a;ht…

allegro中shape的一些基本操作(一)——添加和修改shape

添加shape 简单添加shape的方式有3种&#xff0c;如下图所示 点击选择相应的shape模式后可以在option面板中设置相应的shape参数&#xff08;这里不做过多介绍&#xff0c;里面可以设置shape的大小、静态或动态shape等参数&#xff09;&#xff0c;然后再用鼠标在相应的层上添…

2022最新版-李宏毅机器学习深度学习课程-P17 卷积神经网络CNN

一、CNN 用于图像分类 需要图片大小统一 彩色图像分为R G B 三层&#xff0c;展平后首尾相接 值代表着颜色的强度 图像识别中不需要全连接的&#xff0c;参数太多了 观测1&#xff1a;通过判断多个小局部图像就能判断出图片标签 感受野的定义 简化1 感受野可以重叠&#xff…

MyBatisPlus的学习项目页面

MyBatisPlus通过扫描实体类&#xff0c;并基于反射获取实体类信息作为数据库表信息 类名驼峰转下划线作为表名 名为id的字段作为主键 变量名驼峰转下划线作为表的字段名 常见注解 TableName&#xff1a;用来指定表名 Tableld&#xff1a;用来指定表中的主键字段信息 Tabl…

Linux:Mac VMware Fusion13以及CentOS7安装包

Linux&#xff1a;Mac VMware Fusion13以及CentOS7安装包 1. Mac VMware Fusion132. CentOS7安装包3. 安装 1. Mac VMware Fusion13 下载官网地址&#xff1a;https:www.vmware.com/products/fusion/fusion-evaluation.html 2. CentOS7安装包 注意是m芯片需要使用arm架构的i…

周记之学习总结

你在人群中看到的每一个耀眼的女孩&#xff0c;都是踩着刀尖过来的。你如履平地般地舒适坦然&#xff0c;当然不配拥有任何光芒&#xff1b; 10.11-10.12 思来想去还是不舍得&#xff0c;搞了一下这个jwt&#xff0c;看了很多视频和博客&#xff0c;一直没看懂&#xff0c;两…

使用VS Code终端窗口创建Python虚拟环境

在日常的Python开发中&#xff0c;管理项目的依赖关系是至关重要的。一个非常有用的工具是Python虚拟环境&#xff0c;它允许我们可以在同一计算机上隔离不同项目的依赖&#xff0c;以确保它们不会相互干扰。在本文中&#xff0c;我们将介绍如何在VS Code终端窗口中使用命令mkv…

Ubuntu:VS Code IDE安装ESP-IDF【保姆级】

物联网开发学习笔记——目录索引 参考&#xff1a; VS Code官网&#xff1a;Visual Studio Code - Code Editing. Redefined 乐鑫官网&#xff1a;ESP-IDF 编程指南 - ESP32 VSCode ESP-ID Extension Install 一、前提条件 Visual Studio Code IDE安装ESP-IDF扩展&…

随机误差理论与测量

文章目录 第1节 随机误差的性质和特点第2节 随机误差的数字特性标准差的估计 第3节 单次测量结果的精度指标第4节 多次测量结果的精度指标算数平均值的分布特性与标准差算数平均值的置信度算数平均值的精度指标&#xff08;常用的有4个) 第5节 非等精度测量 第1节 随机误差的性…