react 路由跳转(声明式导航)

1,182 阅读5分钟

一、项目初始化准备

1、创建与启动

  • npx create-react-app react-router
  • cd react-router
  • yarn start 或 npm start 或 npm run start
  • 新建 src/components/ComRouter.js
  • yarn add react-router-dom@5.2.1

image.png

特别注意:如果是 react-router-dom 的版本过高,写法会有所变化。

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、App.js

import React from 'react'
// 导入 ComRouter 组件
import ComRouter from './components/ComRouter'
class App extends React.Component {
  render() {
    return <div>
      <ComRouter></ComRouter>
    </div>
  }
}
export default App

二、路由初体验

1、在ComRouter.js 中 log 一下 路由里面的东西

import React from 'react'

// yarn add react-router-dom@5.2.1
import * as obj from 'react-router-dom'

class ComRouter extends React.Component {
    render() {
        console.log(obj,'路由呀')
        return <div>
            <p>我是 ComRouter</p>
        </div>
    }
}
export default ComRouter

2、查看打印结果,先自己摸索一下

image.png

3、重点数据说明

  • BrowserRouter :history 路由
  • HashRouter :hash 路由
  • Link :相当于 vue 中的 router-link
    • to 属性,将来会渲染成 a 标签的 href 属性
    • Link 组件无法实现导航的高亮效果
  • Route :相当于 vue 中的 router-view
  • NavLink :一个更特殊的 Link 组件,可以用于指定当前导航高亮
    • to属性 :用于指定地址,会渲染成 a 标签的 href 属性
    • activeClass :用于指定高亮的类名,默认 active
    • exact :精确匹配,表示必须精确匹配类名才生效

4、在ComRouter.js 开始配置一级路由测试一下

import React from 'react'

// 导入 react-router-dom
import { BrowserRouter, Link, Route } from 'react-router-dom'

// 配置一级路由
const First = () => {
    return <div>
        编程不仅仅是技术,还是艺术!First
    </div>
}

const Second = () => {
    return <div>
        编程不仅仅是技术,还是艺术!Second
    </div>
}

const Third = () => {
    return <div>
        编程不仅仅是技术,还是艺术!Third
    </div>
}

// ◆ BrowserRouter 只能出现一次
class ComRouter extends React.Component {
    render() {
        return <div>
            <p>我是 ComRouter</p>
            <BrowserRouter>
                <ul>
                    <li><Link to='/first'>我是 first</Link></li>
                    <li><Link to='/second'>我是 second</Link></li>
                    <li><Link to='/third'>我是 third</Link></li>
                </ul>
                <div className="box">
                    <Route path="/first" component={First}></Route>
                    <Route path="/second" component={Second}></Route>
                    <Route path="/third" component={Third}></Route>
                </div>
            </BrowserRouter>
        </div>
    }
}
export default ComRouter

image.png

三、路由进阶

1、进阶需求:

  • 实现导航高亮 NavLink
  • 路由重定向到 First 组件
  • 实现 404 页面

2、引入Switch 组件 和 exact 属性

  • 通常,我们会把 Route 包裹在一个 Switch 组件中
  • Switch 组件中,不管有多少个路由规则匹配到了,都只会渲染第一个匹配的组件
  • 通过 Switch 组件非常容易的就能实现 404 错误页面的提示
  • Route 设置 exact 属性, 实现精确匹配

3、新建 src/index.css 设置导航高亮的样式

.active {
    background-color: pink;
}

4、开始改装 ComRouter.js

import React from 'react'
// ◆ 导入 样式
import '../index.css'
// ◆ 导入 react-router-dom
import { BrowserRouter, NavLink, Route, Switch ,Redirect} from 'react-router-dom'

const First = () => {
    return <div>
        编程不仅仅是技术,还是艺术!First
    </div>
}

const Second = () => {
    return <div>
        编程不仅仅是技术,还是艺术!Second
    </div>
}

const Third = () => {
    return <div>
        编程不仅仅是技术,还是艺术!Third
    </div>
}

// ◆ 404 页面
const NotFound = () => {
    return <div>
        404  NOTFOUND
    </div>
}

class ComRouter extends React.Component {
    render() {
        return <div>
            <p>我是 ComRouter</p>
            <BrowserRouter>
                <ul>
                    {/* ◆ 导航高亮 NavLink */}
                    <li><NavLink to='/first'>我是 first</NavLink></li>
                    <li><NavLink to='/second'>我是 second</NavLink></li>
                    <li><NavLink to='/third'>我是 third</NavLink></li>
                </ul>
                <div className="box">
                    <Switch>
                        {/* <Route exact path="/" component={First}></Route> */}
                        {/* ◆ 路由重定向 */}
                        <Redirect exact from="/" to="/First"></Redirect>
                        <Route path="/first" component={First}></Route>
                        <Route path="/second" component={Second}></Route>
                        <Route path="/Third" component={Third}></Route>
                        {/* ◆ 404页面 */}
                        <Route component={NotFound}></Route>
                    </Switch>
                </div>
            </BrowserRouter>
        </div>
    }
}
export default ComRouter

image.png

四、再度进阶

1、进阶需求

  • 抽离各个组件为单独的 js 文件
  • 实现二级路由跳转:Second 下新增:Web、Java、Ui 页面

2、新建一级路由文件夹及相关文件

  • src/components/Pages/First.js
  • src/components/Pages/Second.js
  • src/components/Pages/Third.js
  • src/components/Pages/NotFound.js

image.png

3、一级路由内容(初始调整)

First.js 还是函数组件

import React from 'react'

const First = () => {
    return <div>
        编程不仅仅是技术,还是艺术!First
    </div>
}
export default First

Second.js 调整为类组件

import React from 'react'

class Second extends React.Component {
    render() {
        return <div>
            编程不仅仅是技术,还是艺术!Second
        </div>
    }
}
export default Second

Third.js 调整为类组件

import React from 'react'

class Third extends React.Component {
    render() {
        return <div>
            编程不仅仅是技术,还是艺术!Third
        </div>
    }
}
export default Third

NotFound.js 还是函数组件

const NotFound = () => {
    return <div>
        404  NOTFOUND
    </div>
}
export default NotFound

ComRouter.js 导入

import React from 'react'
// 导入 样式
import '../index.css'
// 导入 react-router-dom
import { BrowserRouter, NavLink, Route, Switch } from 'react-router-dom'
// 导入
import First from './Pages/First'
import Second from './Pages/Second'
import Third from './Pages/Third'
import NotFound from './Pages/NotFound'

class ComRouter extends React.Component {
    render() {
        return <div>
            <p>我是 ComRouter</p>
            <BrowserRouter>
                <ul>
                    <li><NavLink to='/first'>我是 first</NavLink></li>
                    <li><NavLink to='/second'>我是 second</NavLink></li>
                    <li><NavLink to='/third'>我是 third</NavLink></li>
                </ul>
                <div className="box">
                    <Switch>
                        <Route exact path="/" component={First}></Route>
                        <Route path="/first" component={First}></Route>
                        <Route path="/second" component={Second}></Route>
                        <Route path="/Third" component={Third}></Route>
                        <Route component={NotFound}></Route>
                    </Switch>
                </div>
            </BrowserRouter>
        </div>
    }
}
export default ComRouter

4、配置二级路由

1.新建二级路由文件夹及文件

  • src/components/Pages/Second/Web.js
  • src/components/Pages/Second/Java.js
  • src/components/Pages/Second/Ui.js

image.png

2.二级路由内容

Web.js

const Web =()=>{
    return <div>我是 Web</div>
}
export default Web

Java.js

const Java =()=>{
    return <div>我是 Java
    </div>
}
export default Java

Ui.js

const Ui =()=>{
    return <div>我是 Ui</div>
}
export default Ui

3.改装 Second.js

import React from 'react'
// 导入 react-router-dom
import { Link, Route, Switch } from 'react-router-dom'

// 导入二级路由组件
import Web from './Second/Web'
import Java from './Second/Java'
import Ui from './Second/Ui'

class Second extends React.Component {
    render() {
        return <div>
            编程不仅仅是技术,还是艺术!Second
            <ul >
                <li><Link to='/second/web'>web</Link></li>
                <li><Link to='/second/java'>java</Link></li>
                <li><Link to='/second/ui'>ui</Link></li>
            </ul>
            <div className="box">
                <Switch>
                    <Route path="/second/web" component={Web}></Route>
                    <Route path="/second/java" component={Java}></Route>
                    <Route path="/second/ui" component={Ui}></Route>
                </Switch>
            </div>
        </div>
    }
}
export default Second

image.png

五、传参及获参

第一种方法:search

1.Second.js 传递参数

// 省略其他。。。

<li><Link to='/second/web?name=Lucy&age=18'>web</Link></li>

2.Web.js 获取参数

const Web = (props) => {
    console.log(props, 'Web')
    // console.log(props,'路由传参web')
    console.log(props.location.search)//?name=Lucy&age=18
    //  如果我们想获取 name 和 age,怎么办?
    // ◆法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 封装成函数
    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>我是 Web
        {/* 法1:利用浏览器内置方法*/}
        <p>我的名字是:{name} 我的年龄是:{age}</p>
        {/* 法2:截取、切割、循环 */}
        <p>我的名字是:{obj.name} 我的年龄是:{obj.age}</p>
        {/* 法3:封装成函数 */}
        <p>我的名字是:{res.name} 我的年龄是:{res.age}</p>
    </div>
}
export default Web

image.png

第二种方法:params (附带 search )

1.Second.js 传递参数

// 省略其他。。。

<li><Link to='/second/java/2/rose?age=25'>java</Link></li>

<Route path="/second/java/:id/:name" component={Java}></Route>

2.Java.js 获取参数

const Java = (props) => {
    // 1.接收 params 参数
    const id = props.match.params.id
    const name = props.match.params.name
    // 2.接收 search 参数
    console.log(props.location.search, 'Java')// ?age=25
    const age = new URLSearchParams(props.location.search).get('age')
    // 3.显示在页面
    return <div>我是 Java
        <p>我的id 是{id},我的名字是{name}</p>
        <p>我的年龄是{age}</p>
    </div>
}
export default Java

image.png

第三种方法:query

1.Second.js 传递参数

 <li><Link to={{pathname:'/second/ui',query:{name:'Jack'}}}>ui</Link></li>

2.Ui.js 获取参数

const Ui = (props) => {
    console.log(props, 'Ui')
    // 1.获取 query 参数
    const name = props.location.query.name
    // 2.显示在页面
    return <div>我是 Ui
        <p>我的名字是 {name}</p>
    </div>
}
export default Ui

image.png

第四种方法:state(类似 query)

1.Second.js 传递参数

  {/* <li><Link to={{pathname:'/second/ui',query:{name:'Jack'}}}>ui</Link></li> */}
      <li><Link to={{pathname:'/second/ui',state:{name:'Mini'}}}>ui</Link></li>

2.Ui.js 获取参数

const Ui = (props) => {
    console.log(props, 'Ui')
    // 1.获取 query 参数
    // const name = props.location.query.name
    // 1.获取 state 参数
    const name = props.location.state.name
    // 2.显示在页面
    return <div>我是 Ui
        <p>我的名字是 {name}</p>
    </div>
}
export default Ui

image.png