react 路由跳转(编程式导航)

13,578 阅读3分钟

一、项目需求

准备实现一个简易的编程式导航项目,需求如下

  • 一级路由:Login 、Layout
  • 二级路由:Layout 下有 Avatar、Detail、User
  • 实现登录、退出跳转功能
  • 实现传参获参:Avatar、Detail、User

二、项目初始化准备

1.创建启动下载

  • npx create-react-app react-router
  • cd react-router
  • yarn start 或 npm start 或 npm run start
  • yarn add react-router-dom@5.2.1

image.png

2.index.js

import React from 'react'
import ReactDOM from 'react-dom'

import App from './App'

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
)

3.子路由文件基本内容

src/views/Page/Avatar.js

// 函数组件
const Avatar = () => {
    return <div>
        <p>我是 Avatar</p>
    </div>
}
export default Avatar

src/views/Page/Detail.js

// 类组件
import React from 'react'

class Detail extends React.Component {
    render() {
        return <div>
            <p>我是 Detail </p>
        </div>
    }
}
export default Detail

src/views/Page/User.js

// 类组件
import React from 'react'

class User extends React.Component {
    render() {
        return <div>
            <p>我是 User </p>
        </div>
    }
}
export default User

4.补充导航点击样式 index.css

/* 点击出现小手 */
li {
    width: 100px;
    cursor: pointer;
    
}
/* 点击导航高亮 */
li:hover {
    background-color: pink;
}

三、实现编程式导航跳转

1.App.js

import React from 'react'
// 导入路由 react-router-dom@5.2.1
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom'
// 导入登录页
import Login from './views/Login'
// 导入首页
import Layout from './views/Layout'

// ◆BrowserRouter 只能出现一次
class App extends React.Component {
  render() {
    return <div>
      <BrowserRouter>
        <Switch>
          <Route exact path="/login" component={Login} ></Route>
          <Route path="/layout" component={Layout} ></Route>
          {/* 重定向 */}
          <Redirect exact from="/" to="login"></Redirect>
        </Switch>
      </BrowserRouter>
    </div>
  }
}
export default App

2.src/views/Login.js

函数组件实现编程式导航跳转

import React from 'react'
import { Route } from 'react-router-dom'
import Layout from './Layout'

const Login = (props) => {
    // 1.登录 去 Layout
    const goLayoutHandler = () => {
        props.history.push('/layout')
    }
    return <div>
        <p>这是登录页!  Login</p>
        <button onClick={goLayoutHandler}>登录</button>
        <Route path="/layout" component={Layout}></Route>
    </div>
};
export default Login

3.src/views/Layout.js

类组件实现编程式导航跳转

import React from 'react'
import { Route, Redirect } from 'react-router-dom'
// 导入 子路由
import Avatar from './Page/Avatar'
import Detail from './Page/Detail'
import User from './Page/User'
import '../index.css'

class Layout extends React.Component {
    // ◆1.退出登录
    logOutHandler = () => {
        this.props.history.push('/login')
    }
    // ◆2.去 Avatar
    goAvatatHandler = () => {
        this.props.history.push('/layout/avatar')
    }
    // ◆3.去 Detail
    goDetailHandler = () => {
        this.props.history.push('/layout/detail')
    }
    // ◆4.去 User
    goUserHandler = () => {
        this.props.history.push('/layout/user')
    }
    render() {
        return <div>
            <div>
                <p>这是首页!  Layout</p>
                <button onClick={this.logOutHandler}>退出</button>
            </div>
            <div >
                <ul>
                    <li onClick={this.goAvatatHandler}>我是 Avatar</li>
                    <li onClick={this.goDetailHandler} >我是 Detail</li>
                    <li onClick={this.goUserHandler}>我是 User</li>
                </ul>
                <div className="box">
                    <Redirect from="/layout" to="/Layout/avatar"></Redirect>
                    <Route path="/layout/avatar" component={Avatar}></Route>
                    <Route path="/layout/detail" component={Detail}></Route>
                    <Route path="/layout/user" component={User}></Route>
                </div>
            </div>
        </div>
    }
}
export default Layout

四、编程式导航传参与获参

第一种:search

1.Layout.js 传参

// 省略其他。。。
// ◆2.去 Avatar
    goAvatatHandler = () => {
        this.props.history.push('/layout/avatar?name=Lucy&age=18')
    }

2.Avatar.js 获参

const Avatar = (props) => {
    console.log(props,'Avatar')
    console.log(props.location.search)//?name=Lucy&age=18
    // ◆法1:浏览器内置的 new URLSearchParams() 方法,获取我们想要的参数 
    const name = new URLSearchParams(props.location.search).get('name')
    const age = new URLSearchParams(props.location.search).get('age')
    console.log(name)// Lucy
    console.log(age)// 18

    // ◆法2:slice()方法,可用于字符串和数组(我还想变成对象的格式)
    // 1.把问号去掉
    const query = props.location.search.slice(1)
    console.log(query, 'query')// name=Lucy&age=18
    // 2.切割成数组
    const arr = query.split('&')
    console.log(arr, 'res')// 'name=Lucy', 'age=18'] 'res'
    // 3.再循环切割获取对象
    let obj = {}
    arr.forEach(item => {
        const arr2 = item.split(['='])
        console.log(arr2, 'arr2')// ['name','Lucy'] ['age','18']
        obj[arr2[0]] = arr2[1]
    })
    console.log(obj, 'obj')// {name: 'Lucy', age: '18'}

    // ◆法3:把 法2 封装成函数(也可以单独抽离成一个 js 文件)
    function paramsQuery(url) {
        // 1.把问号去掉
        const query = url.slice(1)
        // 2.切割成数组
        const arr = query.split('&')
        // 3.再循环切割获取对象
        let newObj = {}
        arr.forEach(item => {
            const arr2 = item.split(['='])
            newObj[arr2[0]] = arr2[1]
        })
        //   const {name,age}=obj
        // 4.返回对象
        return newObj
    }
    // 5.调用获取结果
    const res = paramsQuery(props.location.search)
    console.log(res, '123')

    // ◆ 页面使用
    return <div>
        <p>我是 Avatar</p>
        <p>我的名字是{name},我的年龄是:{age}</p>
        <p>我的名字是{obj.name},我的年龄是:{obj.age}</p>
        <p>我的名字是{res.name},我的年龄是:{res.age}</p>
    </div>
}
export default Avatar

3.页面效果

image.png

第二种:params(附search)

1.Layout.js 传参

// 省略其他。。。
// ◆3.去 Detail
    goDetailHandler = () => {
        this.props.history.push('/layout/detail/2/Rose?age=20')
    }
    
    <Route path="/layout/detail/:id/:name" component={Detail}></Route>

2.Detail.js 获参

import React from 'react'

class Detail extends React.Component {
    // 1.定义变量接收传递过来的 params 参数和 search 参数
    state = {
        id: this.props.match.params.id,
        name: this.props.match.params.name,
        friend: new URLSearchParams(this.props.location.search).get('friend')
    }
    // 2.显示渲染在页面
    render() {
        console.log(this.props, 'Detail')
        return <div>
            <p>我是 Detail </p>
            <p>我的 id 是:{this.state.id} ,我的名字的:{this.state.name}</p>
            <p>我的朋友是:{this.state.friend}</p>
        </div>
    }
}
export default Detail

3.页面效果

image.png

第三种:query

1.Layout.js 传参

// ◆4.去 User
    goUserHandler = () => {
        this.props.history.push({pathname:'/layout/user',query:{name:'Jack'}})
    }

2.User.js 获参

import React from 'react'

class User extends React.Component {
    state={
        name:this.props.location.query.name
    }
    render() {
        return <div>
            <p>我是 User </p>
            <p>我的名字是:{this.state.name}</p>
        </div>
    }
}
export default User

3.页面效果

image.png

第四种:state(同 query)

1.Layout.js 传参

// ◆4.去 User
    goUserHandler = () => {
        // this.props.history.push('/layout/user')
        // this.props.history.push({pathname:'/layout/user',query:{name:'Jack'}})
        this.props.history.push({pathname:'/layout/user',state:{ids:3}})
    }

2.User.js 获参

import React from 'react'

class User extends React.Component {
    state={
        ids:this.props.location.state.ids
    }
    render() {
        return <div>
            <p>我是 User </p>
            <p>我的 ids 是:{this.state.ids}</p>
        </div>
    }
}
export default User

3.页面效果

image.png