React 路由传参_react-router-dom 的使用_自定义导航的三种方式_withRouter()

1. React Router

React Router包含了四个包:

包名 描述
react-router React Router 核心api
react-router-dom React Router的DOM绑定,在浏览器中运行不需要额外安装 react-router
react-router-native React Native中使用,而实际的应用中,其实不会使用这个。
react-router-config 静态路由的配置

主要使用 react-router-dom

2. React Router基本原理

React Router 甚至大部分的前端路由都是依赖于 history.js 的,它是一个独立的第三方js库。可以用来兼容在不同浏览器、不同环境下对历史记录的管理,拥有统一的 API。

//默认使用的是history模式
import { BrowserRouter as Router} from 'react-router-dom';
//更改为hash模式
import { HashRouter as Router} from 'react-router-dom';
  • 老浏览器的 history: 通过 hash 来存储在不同状态下的 history 信息,对应 createHashHistory ,通过检测 location.hash 的值的变化,使用 location.replace 方法来实现 url 跳转。通过注册监听 window 对象上的 hashChange 事件来监听路由的变化,实现历史记录的回退。
  • 高版本浏览器: 利用 HTML5 里面的 history,对应 createBrowserHistory ,使用包括 pushStatereplaceState 方法来进行跳转。通过注册监听 window 对象上的 popstate 事件来监听路由的变化,实现历史记录的回退。
  • node环境下: 在内存中进行历史记录的存储,对应 createMemoryHistory。直接在内存里 pushpop 状态。

3. 使用

在终端中执行下面的命令,安装 react-router-dom,-S 表示在生产环境使用
yarn add react-router-dom -S

3.1 基本使用

  • <Link> 默认会被解析成 a标签,相当于vue中的 <router-link>;
  • <Route>标签中,渲染组件可以使用 component 属性,也可以使用 render() 函数,使用 component 的方式是不能直接在组件上添加属性的,可以使用 render() 函数,这个常用于页面组件级别的权限管理;
  • 函数组件和 render() 函数默认接收一个props参数,通过 props.match.params 可以获取 url的动态参数;
  • <Route>标签中,exact 属性表示严格匹配,为 false 时表示模糊匹配;
  • <Redirect>标签,通过设置 from 和 to 属性值,进行路由跳转;
  • <Switch>标签的作用是排他性,从上往下按顺序匹配路由,匹配成功后,就不再往下找了;
  • 路由传参,有动态参数(如 /:id)params 参数(如 /name=zz&age=18) 两种方式,可以通过 props 属性来获取传递的内容;
  • 多视图概念,如果不使用<Switch>标签的话,所有匹配成功的路由都会显示其渲染的内容;
  • 嵌套路由,在子组件中路由使用方法和父组件中一致,不同的是子组件中最外层不需要再使用<Router>标签;
  • 404页面通常配置在最下面,<Route>标签中 path 属性值为" * ",也可以不写 path,表示全部匹配;
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import {
  BrowserRouter as Router, //设置别名为 Router
  Route,
  Link,
  Redirect,
  Switch,
  useLocation
} from 'react-router-dom'

const Home = () => {
  return <h1>Home page</h1>
}
const About = (props) => {
  //函数组件默认接收一个 props参数
  //以下三种方式都可以获取 url中的参数
  let query1=props.location.search;
  let query2=useLocation().search;
  let query3=window.location.search;
  //打印结果都为 ?city=beijing&code=18
  console.log(query1,query2,query3);
  //通过 new URLSearchParams()获取参数的值
  let query=new URLSearchParams(useLocation().search).get('city')
  return <h1>About page,city:{query}</h1>
}
const Login = () => {
  return <h1>Login page</h1>
}

class Page extends Component {
  render() {
    return (
      <Router>
        {/* Link 默认会被解析成 a标签 */}
        <Link to="/home">首页</Link>
        <Link to="/about/?city=beijing&code=18">关于我们</Link>
        <Link to="/product/34">产品</Link>
        <Link to="/login">登录</Link>
        <hr />
        {/* Switch 的作用是从上往下匹配路由,匹配成功后,就不再往下找了 */}
        <Switch>
          {/* 渲染组件可以使用 component,也可以使用 render()函数 */}
          <Route path="/home" component={Home}></Route>
          <Route path="/about" component={About}></Route>
          <Route path="/login" component={Login}></Route>
          
          <Route path="/product/:id" render={(props)=>{
            //默认接收一个props参数,通过 props.match.params获取 url的动态参数
            return <h1>Product page,id:{props.match.params.id}</h1>
          }}></Route>
          
          {/* exact 表示精确匹配 */}
          <Redirect exact from="/" to="/home"></Redirect>
          
          <Route path="*" render={() => {
            return <div>404 page not found...</div>
          }}></Route>
          
        </Switch>
      </Router>
    )
  }
}
ReactDOM.render(
  <Page/>,
  document.getElementById('root')
);

3.2 路由权限验证

在 vue 中,我们可以使用 router.beforeEach 做路由的权限验证,在 react 中,可以通过 render() 函数做逻辑处理,来实现这个功能。

例如,当用户是未登录状态时,可以访问首页内容,当访问用户管理页面时,跳转至登陆页,代码如下:

import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter as Router, Route, Link } from 'react-router-dom'

const Home = () => <h1>Home page</h1>
const Login = () =>  <h1>Login page</h1>
const User = () => <h1>user page</h1>

export default class Page extends Component {
  constructor() {
    super();
    //routers 相当于是路由配置文件
    this.routers = [
      {path: "/home", component: Home, auth: false},
      {path: "/login", component: Login, auth: false}, 
      {path: "/user", component: User, auth: true}
    ]
  }
  render() {
    return (
      <Router>
        <Link to="/home">首页</Link>
        <Link to="/user">用户管理</Link>
        
        {
          this.routers.map((item, index) => {
            return <Route key={index} path={item.path} render={() => {
            //判断当前跳转的路由是否需要进行验证
              return item.auth ? <Login></Login> : <item.component></item.component>
            }}>
            </Route>
          })
        }
      </Router>
    )
  }
}
ReactDOM.render(
  <Page/>,
  document.getElementById('root')
);

3.3 设置路由选中状态

通过设置 react-router-dom 中自带的 <NavLink> 标签的 activeClassName 属性,可以动态设置当前页面路由标签的选中样式;也可以通过下面自定义导航的方式实现当前页面路由标签的选中样式。

<NavLink activeClassName="active" to="/home">首页</NavLink>
<NavLink activeClassName="active" to="/about">关于我们</NavLink>

3.4 自定义导航

在 react-router-dom 中,<Link> 标签默认会被解析成 a 标签,如果想以 <li> 标签或者别的标签展示,就可以通过自定义导航来实现;自定义导航也可以设置当前页面路由标签的选中样式。设置自定义导航有以下几种方式:

3.4.1 方式一

创建自定义组件,通过将<Link>标签包裹,完成自定义导航。

const CustomLink = (prop) => {
  return (
    <li>
      <Link to={prop.path}>{prop.name}</Link>
    </li>
  )
}
<CustomLink path="/home" name="首页"></CustomLink>

3.4.2 方式二

通过 withRouter()高阶函数,可以拿到路由的上下文信息,并对当前组件功能做增强,这种方式用起来更灵活,藕合性低。

通过 this.props.history.push() 可以实现编程式导航页面跳转。

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

class About extends Component {
  handleClick = () => {
    //编程式导航
    this.props.history.push(this.props.path)
  }
  render() {
    return (
      <li className={this.props.path === this.props.location.pathname ? 'active':''} onClick={this.handleClick}>
        关于我们
      </li>
    )
  }
}
export default withRouter(About)

在入口文件中引用:

import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter as Router } from 'react-router-dom'
import About from './About'

const Index=()=>{
	return (
		<Router>
			<About path="/about"></About>
		</Router>
	)
}
ReactDOM.render(
  <Index/>,
  document.getElementById('root')
);

注意:

  • withRouter() 只能作在类组件中
  • withRouter() 使用时,需要放在<Router>标签内,否则会报下面的错
    react-router-dom 的使用

3.4.3 方式三

  • 通过 <Route> 标签的 children 属性,可以进行逻辑操作,将<Link>标签包裹,以及用来判断当前标签是否被选中。
  • children() 用法和 render() 类似。
  • 不管是什么路由匹配,只要点击路由标签,children 里面的函数都会被执行。
  • 如果 <Route> 标签上有 children 属性,则 props.match 有值,否则 props.match 为 null。
<Route path="/product" children={(props)=>{
    return <Link className={props.match?'active':''} to="/product">产品</Link>
   }}></Route>

自定义导航三种方式汇总:

import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import {BrowserRouter as Router,Route,Link,NavLink} from 'react-router-dom'

import About from './About' //About.jsx 文件同上面3.4.2中

const CustomLink = (props) => {
  return <li><Link to={props.path}>{props.name}</Link></li>
}

class Page extends Component {
  render() {
    return (
      <Router>
        <ul>
          //方式一
          <CustomLink path="/home" name="首页"></CustomLink>
          //react-router-dom 自带标签
          <NavLink activeClassName="active" to="/login">登录</NavLink>
          //方式二
          <About path="/about"></About>
          //方式三
          <Route path="/product" children={(props)=>{
            return <Link className={props.match?'active':''} to="/product">产品</Link>
          }}></Route>
        </ul><hr/>

        <Route exact path="/home"><h1>首页</h1></Route>
        <Route exact path="/login"><h1>登录</h1></Route>
        <Route exact path="/about"><h1>关于我们</h1></Route>
        <Route exact path="/product"><h1>产品</h1></Route>
      </Router>
    )
  }
}
ReactDOM.render(
  <Page/>,
  document.getElementById('root')
);

页面效果如下,点击上面的导航,在下方显示对应内容,并且该导航标签上增加 active 的样式(这里设置选中导航字体为红色)。
react-router-dom 的使用

猜你喜欢

转载自blog.csdn.net/Charissa2017/article/details/105722727