IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> React路由详解 -> 正文阅读

[JavaScript知识库]React路由详解

1.什么是路由

一个路由其实就是一个映射关系(k:v)

key为路径,value可能是function 或者是 component

(1)后端路由:

value是function,用来处理客户端提交的请求

注册路由:router.get(path,function(req,res))

工作过程:当node接收一个请求的时候,根据请求路径找到匹配的路由,调用路由中的函数来处理请求,返回响应的数据

(2)前端路由:

浏览器端路由,value是Component,用于展示页面内容

注册路由:< Route path="/test" component={Test}>

工作过程:当浏览器的path变为/test的时候,当前路由组件就会变成Test组件

(3)前端路由的原理

这个主要是依靠于history,也就是浏览器的历史记录。

浏览器上的记录其实就是一个栈,前进一次就是入栈,后退一次就是出栈。

并且历史记录上有一个监听的方法,可以时时刻刻监听记录的变化。从而判断是否改变路径

History

SPA

单页Web应用(single page web application,SPA)。整个应用只有一个完整的页面。

点击页面中的链接不会刷新页面,只会做页面的局部更新。

数据都需要通过ajax请求获取,并在前端异步展现

2.使用 react-router

(1) 安装与使用

在项目文件夹中打开命令行窗口进行 npm下载

npm i react-router-dom -S
复制代码

注意:我们下载的是 react-router-dom 而不是 react-router 两者区别:

  • react-router:提供了router的核心 API。如RouterRouteSwitch等,但没有提供有关dom操作进行路由跳转的API
  • react-router-dom:提供了BrowserRouterRouteLink等api,可以通过dom操作触发事件控制路由

react-router-dom中包含了react-router,所以我们选择下 react-router-dom

(2) 常用组件

a. 路由跳转

在多页面应用中,通常都是使用 a标签进行页面跳转

<a href="http://localhost:3000">跳转页面</a>
复制代码

使用单页面富应用中使用react-router则使用路由跳转组件

import {Link, NavLink} from "react-router";
复制代码
<Link activeClassName="nav-active" className="nav" to="/about">About</Link>
<NavLink activeClassName="nav-active" className="nav" to="/home">Home</NavLink>
复制代码
  • activeClassName: 处于当前路由时,对应的组件会自动添加该类
  • className: 当前组件类名
  • to: 当前组件所对应的路由

Link组件与 NavLink组件都可以进行路由的跳转,区别在于:当前路由对应的NavLink会自动添加class: active,而 Link不会。

b. 注册路由

import {Route} from "react-router";
复制代码
<Route path="/home" component={Home}></Route>
<Route exact path="/about" component={About}></Route>
复制代码
  • path: 所要监听的路由
  • component: 该路由要绑定的组件
  • exact: 可选,不写时为 false,是否选择严格匹配

当当前路由对应上了路由组件所绑定的路由时,则会展示所绑定的组件。

模糊匹配和精准匹配

react默认是开启模糊匹配的。

比如:

<MyNavLink to = "/home/a/b" >Home</MyNavLink>

此时该标签匹配的路由,分为三个部分 home a b;将会根据这个先后顺序匹配路由。

如下就可以匹配到相应的路由:

<Route path="/home"component={Home}/>

但是如果是下面这个就会失败,也就是说他是根据路径一级一级查询的,可以包含前面那一部分,但并不是只包含部分就可以。

<Route path="/a" component={Home}/>

当然也可以使用这个精确的匹配 exact={true}

如以下:这样就精确的匹配/home,则上面的/home/a/b就不行了

<Route exact={true}  path="/home" component={Home}/>
或者
<Route exact path="/home" component={Home}/>

c. 重定向路由

你明明设置好了路由 /home,但是有的用户就喜欢对着干,在地址栏输入了 /nothing,而你没有注册这个路由,那该怎么办呢?
这个时候你就可以东涌道重定向路由了,对于没有注册过的路由,都会被跳转到你指定的某个路由去,这就是重定向路由
经常可以用作一些404页面丢失等情况的路由跳转方式。

import {Redirect, Route} from "react-router";
复制代码
<Route ....../>
<Route ....../>
<Redirect to="/home"/>
复制代码
  • to: 需要重定向到哪个路由?

Redirect需放在所有Route下面,当上面的 Route都没有匹配到时,则路由将重定向到指定的路由。

d. Switch 路由

你想想,如果你的路由中,出现了 /home/home/abc/home/a/b/c 等这样的路由,当路由为 /home时则会三个路由都同时渲染,但是你又只想要渲染其中的一条,这个时候我们就可以使用 Switch组件。
使用 Switch组件包裹住所有的 RouteRedirect,当出现多个匹配的路由时,只会渲染第一个匹配的组件。

import {Switch, Route, Redirect} from "react-router";
复制代码
<Switch>
    <Route ..../>
    <Route ..../>
    <Redirect to="..."/>
</Switch>

e. 路由器

你想要使用路由跳转组件和路由组件,还差一个路由器组件,同时路由器组件必须包裹着这两个组件。

import {HashRouter, BrowserRouter} from "react-router";
复制代码

一般为了使整个React应用都可以使用到路由组件,所以一般我们都是把路由器包裹在根组件上的。

ReactDOM.render( 
    <BrowserRouter>
        <App/>
    </BrowserRouter>,
    document.querySelector("#root")
);
复制代码

有两种路由器组件,分别是HashRouterBrowserRouter,分别对应者两种路由方式

(3)路由组件以及一般组件

1.写法不一样

一般组件:< Demo>

路由组件:< Route path="/demo" component ={Demo}/>

2.存放的位置一般不同

一般组件:components

路由组件:pages

3.接收的内容【props】

一般组件:写组件标签的时候传递什么,就能收到什么

路由组件:接收到三个固定的属性【history,location,match】

history:
    go: ? go(n)
    goBack: ? goBack()
    goForward: ? goForward()
    push: ? push(path, state)
    replace: ? replace(path, state)
location:
    pathname: "/about"
    search: ""
    state: undefined

match:
    params: {}
    path: "/about"
    url: "/about"

NavLink

因为Link不能够改变标签体,因此只适合用于一些写死的标签。而如果想要有一些点击的效果,使用NavLink.

如下代码,就写了ctiveClassName,当点击的时候就会触发这个class的样式

{/*NavLink在点击的时候就会去找activeClassName="ss"所指定的class的值,如果不添加默认是active
 这是因为Link相当于是把标签写死了,不能去改变什么。*/}

<NavLink  ctiveClassName="ss" className="list-group-item"  to="/about">About</NavLink>
<NavLink className="list-group-item"  to="/home">Home</NavLink> 

但是可能一个导航又很多标签,如果这样重复的写NavLink也会造成很多的重复性的代码问题。

因此可以自定义一个NavLink:

 // 通过{...对象}的形式解析对象,相当于将对象中的属性全部展开
 //<NavLink  to = {this.props.to} children = {this.props.children}/>
<NavLink className="list-group-item" {...this.props}/>

在使用的时候:直接写每个标签中不一样的部分就行,比如路径和名称

{/*将NavLink进行封装,成为MyNavLink,通过props进行传参数,标签体内容props是特殊的一个属性,叫做children */}
<MyNavLink to = "/about" >About</MyNavLink>

3.嵌套路由

简单来说就是在一个路由组件中又使用了一个路由,就形成了嵌套路由。

举个例子来说:

我们在home这个路由组件中又添加两个组件:

APP.jsx:
<Route   path="/home" component={Home}/>
Home.jsx:
<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/message"/>
    </Switch>
</div>

react中路由的注册是有顺序的,因此在匹配的时候也是按照这个顺序进行的,因此会先匹配父组件中的路由

比如上面的 /home/news的路由处理过程:

1.因为父组件home的路由是先注册的,因此在匹配的时候先去找home的路由,也就是根据/home/news先模糊匹配到/home

2.在去Home组件里面去匹配相应的路由,从而找到了/home/news进行匹配,因此找到了News组件。

但是如果开启精确匹配,就会在第一步的时候卡住,这个时候就走不下去了。因此不要轻易的使用精确匹配

4. 编程式路由

如果说,我们想要做用户点击按钮登陆后,如果他是老师就去老师页面,如果是学生就去学生页面,这个显然单靠 Link 无法完成,我们可以通过 js进行路由的跳转(也是 react-router 基于 History API 编写的)

class Message extends Component {
    state = {
        messageArr:[
            {id:"01", title: "消息1"},
            {id:"02", title: "消息2"},
            {id:"03", title: "消息3"},
        ]
    }
    // 编程式路由导航
    pushShow = (id, title)=>{
        // push跳转 + 携带 params参数
        this.props.history.push(`/home/message/detail/${id}/${title}`);
        
        // push跳转 + 携带 search参数
        // this.props.history.push(`/home/message/detail?id=${id}&title=${title}`);
        
        // push跳转 + 携带 state参数
        // this.props.history.push(`/home/message/detail`, {id,title});
    }
    replaceShow = (id, title)=>{
        // replace跳转 + 携带 params参数
        this.props.history.replace(`/home/message/detail/${id}/${title}`);
        
        // replace跳转 + 携带 search参数
        // this.props.history.replace(`/home/message/detail?id=${id}&title=${title}`);
        
        // replace跳转 + 携带 state参数
        // this.props.history.replace(`/home/message/detail`, {id, title});
    }
    // 后退
    goBack = ()=>{
        this.props.history.goBack();
    }
    // 前进
    goForward = ()=>{
        this.props.history.goForward();
    }
    // 跳转指定位置
    go = ()=>{
        // 向前两步
        this.props.history.go(2);
        
        // 后退两步
        this.props.history.go(-2);
    }
    render() {
        const {messageArr} = this.state;
        return (
            <div>
                <ul>
                    {
                        messageArr.map(item=>{
                            return (
                            <li key={item.id}>
                                <Link to={`/home/message/detail/${item.id}/${item.title}`}>{item.title}</Link>
                                &nbsp;<button onClick={() => this.pushShow(item.id, item.title)}>push查看</button>
                                &nbsp;<button onClick={() => this.replaceShow(item.id, item.title)}>replace查看</button>
                            </li>
                            )
                        })
                    }
                </ul>
                <hr/>
                <Route path="/home/message/detail/:id/:title" component={Detail} />
                <button onClick={this.goBack}>goBack</button>
                &nbsp;
                <button onClick={this.goForward}>goForward</button>
                &nbsp;
                <button onClick={this.go}>go</button>
            </div>
        )
    }
}
复制代码

总结一下上面的代码:

  1. 编程式路由都是通过 props中的 history对象进行操作(都是该对象身上的方法,调用方式为:this.props.history.xxx
  2. 常用方法:
    • push(route[, state]): 跳转到指定路由(带有历史记录)
    • replace(route[, state]): 跳转到指定路由(不带有历史记录)
    • goBack(): 后退一个
    • goForward(): 前进一个
    • go(num): 前往指定步数,当 num为正数时,为前进,当 num为负数时则为后退。

5. withRouter 组件

有的时候,我们想要在其他组件中也使用路由组件的功能,比如导航栏,应该属于公用组件,但是里面的导航链接的功能却是路由组件的功能,我们应该怎么解决呢?
react-router 中,提供了这么一种方法,可以让一般组件具有路由组件的功能,则就是 withRouter() 方法。
看看演示:

import {withRouter} from "react-router-dom";

class Header extends Component {
    // withRouter后该组件也有了路由组件的功能
    goBack = ()=>{
        this.props.history.goBack();
    }
    go = ()=>{
        this.props.history.go(2);
    }
    goForward = ()=>{
        this.props.history.goForward();
    }
    render() {
        return (
            <div>
                <h1>This is a React-router-dom Test!</h1>
                <button onClick={this.goBack}>goBack</button>
                &nbsp;
                <button onClick={this.goForward}>goForward</button>
                &nbsp;
                <button onClick={this.go}>go</button>
            </div>
        )
    }
}

// withRouter 用于给一般组件添加上路由组件特有的功能,返回一个新组件
export default withRouter(Header);
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-30 12:39:12  更:2021-07-30 12:39:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/6 22:34:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码