React(七)- React路由以及嵌套路由的使用

React系列文章导航

前言

在讲React路由前,先来看下SPA的相关概念:

  • SPA:single page web application 单页Web应用。
  • 整个应用只有一个完整的页面。
  • 点击页面中的链接不会刷新页面,只会做页面的局部更新
  • 数据都需要通过Ajax请求获取,并在前端异步展示

一. 路由

路由的概念:

  1. 一个路由就是一个映射关系(key:value)。
  2. key是路径,value可能是一个组件或者一个函数。

路由的分类:

后端路由valueFunction,用来处理客户端提交的请求。

  1. 注册路由:router.get(path,function(req,res))
  2. 工作流程:当node接收到一个请求的时候,会根据请求路径来找到匹配的路由,调用路由中的函数来处理请求,返回相应数据。

前端路由valueComponent组件,用来展示页面内容。

  1. 注册路由:< Route path="/test" component={Test} >
  2. 工作流程:当浏览器的path变为/test的时候,当前路由组件就会变成为Test组件。

1.1 路由的使用

1.安装对应插件react-router-dom

npm install react-router-dom

2.对应项目结构如下:bootstrap.css文件下载地址:提取码:eam4
在这里插入图片描述
index.html文件中引入对应的css文件:

<link rel="stylesheet" href="./bootstrap.css">

About组件:

import React, { Component } from 'react'

export default class About extends Component {
    render() {
        return (
            <div>
                <h2>About</h2>
            </div>
        )
    }
}

Home组件:

import React, { Component } from 'react'

export default class Home extends Component {
    render() {
        return (
            <div>
                <h2>Home</h2>
            </div>
        )
    }
}

App组件:

import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import Home from './components/Home'
import About from './components/About'

export default class App extends Component {
  render() {
    return (
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <div className="page-header"><h2>React Router Demo</h2></div>
          </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" href="./about.html">About</a>
              <a className="list-group-item active" href="./home.html">Home</a> */}
              
              {/**在React中,通过路由链接实现组件的切换 */}
              <Link className="list-group-item" to="/about">About</Link>
              <Link className="list-group-item" to="/home">Home</Link>
            </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>
    )
  }
}

入口文件index.js:

// 引入React核心库
import React from 'react'
// 引入ReactDOM
import ReactDOM from 'react-dom'
// 引入App组件
import App from './App'

import { BrowserRouter } from 'react-router-dom'
// 渲染App到页面
ReactDOM.render(
    <BrowserRouter>
        <App />
    </BrowserRouter>,
    document.getElementById('root')
)

页面效果图如下:
在这里插入图片描述
点击About标签后:页面并不会刷新
在这里插入图片描述
通过上述的案例,做出如下总结:

  1. 我们要明确好界面中的导航区和展示区。
  2. 导航区的a标签改为Link标签:
<Link to="/xxx">Demo</Link>
  1. 展示区和Route标签进行路径的匹配:
<Route path="/xxx" component={组件} />
  1. 要想更加便利的添加一个路由,可将BrowserRouter标签或者HashRouter标签放到App组件的外侧,用于管理整个组件的路由。
ReactDOM.render(
    <BrowserRouter>
        <App />
    </BrowserRouter>,
    document.getElementById('root')
)

可见,上述的案例用的是BrowserRouter,那么如果改为HashRouter会有什么样的效果呢?只需要修改入口文件:
在这里插入图片描述
页面效果如下(只关注地址栏):
在这里插入图片描述
在这里插入图片描述
可以发现,跟BrowserRouter相比,地址栏中多了一个“#”号,两者的区别在后文会详细介绍。

1.2 路由组件和一般组件的区别

案例:我们将上述案例中的提示语单独作为一个Header组件来看看:

import React, { Component } from 'react';

class Header extends Component {
    render() {
        return (
            <div className="page-header"><h2>React Router Demo</h2></div>
        );
    }
}

export default Header;

对应App.jsx文件:改动部分:

import Header from './components/Header'
///....
<div className="row">
    <div className="col-xs-offset-2 col-xs-8">
        <Header />
    </div>
</div>

打开控制台,查看对应组件中的属性,Header组件:
在这里插入图片描述
About组件:
在这里插入图片描述
可以发现,About组件的props属性中含多个键值对,基于此,可以理解为:

  • About组件:就是路由组件。
  • Header组件:就是一般组件。

那么两者有什么区别呢?

  • 写法不同
  1. 一般组件:< Demo/>
  2. 路由组件:< Route path="/demo" component={Demo} >

  • 存放位置不同
  1. 一般组件:components目录
  2. 路由组件:pages目录

  • 接收到的props不同
  1. 一般组件:写组件标签的时候传递了什么,就能收到什么对象/值/函数等。
  2. 路由组件:会接收到三个固定的属性

属性包含:
在这里插入图片描述

1.3 NavLink的使用

上面的案例在页面显示的时候,可以发现一个问题:在点击对应标签的时候,并不会做一个明显的高亮显示,如图:
在这里插入图片描述
那么该如何进行优化呢?最简单的方法,将Link标签改为NavLink,代码修改如下:

import { NavLink, Route } from 'react-router-dom'
<NavLink className="list-group-item" to="/about">About</NavLink>
<NavLink className="list-group-item" to="/home">Home</NavLink>

此时的页面效果:
在这里插入图片描述


若想更改高亮的颜色,那怎么办呢?

对应NavLink标签修改:增加一个activeClassName

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

index.html文件中添加样式:!important代表将当前的样式优先级调成最高。

<style>
    .myHighLight{
        background-color: brown !important;
        color: cornsilk !important;
    }
</style>

页面效果如下:
在这里插入图片描述
问题来了,如果说导航栏比较多,那么对于上述的更改,岂不是每个标签都得加上activeClassName?这样会显得代码很冗余。
在这里插入图片描述
因此,我们需要通过封装NavLink组件来解决上述问题。

1.3.1 封装NavLink组件

定义一个MyNavLink组件:

import React, { Component } from 'react';
import { NavLink } from 'react-router-dom'

class MyNavLink extends Component {
    render() {
        return (
            <NavLink activeClassName="myHighLight" className="list-group-item" {...this.props}>{this.props.children}</NavLink>
        );
    }
}

export default MyNavLink;

App组件中:

<MyNavLink to="/home" a={1} b={2}>Home</MyNavLink>
<MyNavLink to="/about" >About</MyNavLink >

Tip

  1. MyNavLink标签中添加的属性,都会保存到其实例对象的props属性中。
  2. 而我们可以通过语法糖:{....this.props}的方式对其属性进行一一的赋值。
  3. 因此对于这种自定义的组件,我们依旧可以按需来传递参数(比如路由A需要3个参数,而路由B则不需要参数)

总结:

  • NavLink可以实现路由链接的高亮,通过activeClassName指定样式名称。
  • 标签体内容是一个特殊的标签属性。(这里的标签体内容指的是< div >xxx< /div >中的xxx
  • 通过this.props.children可以获得标签体内容。

1.3.2 通过Switch来停止路由匹配

在上述案例的基础上,随意添加一个Test组件:

import React, { Component } from 'react';

class Test extends Component {
    render() {
        return (
            <div>
                <h2>Test</h2>
            </div>
        );
    }
}
export default Test;
``
App组件中添加Test组件:

```javascript
import Test from './components/Test'

并添加一条新的路由:
在这里插入图片描述
那么这种情况下,会发生什么,可见,React将以/homepath的组件全部渲染了。意思就是说,从上到下按照顺序,即使匹配到了对应的路由,但是依旧会往下继续匹配。
在这里插入图片描述

那么这种问题该如何解决?只需要在路由标签的外侧,包一层Switch标签即可。

import { NavLink, Route, Switch } from 'react-router-dom'

在这里插入图片描述
对应的页面效果:可见匹配到对应的路由后,即停止向下匹配。
在这里插入图片描述

对于Switch的使用作出总结:

  1. 通常情况下,pathcomponent是一种一一对应的关系。
  2. Switch可以提高路由匹配的效率(因为是单一匹配

1.3.3 NavLink样式丢失问题

大家有没有发现,上述案例中的路由地址都是一级的,啥意思呢?就是说路由都是"/xxx",而不是"/xxx/xxx",那么如果我将路由地址进行修改,会发生什么?
在这里插入图片描述
看似没什么问题:
在这里插入图片描述
但是如果页面进行刷新,可以发现,样式丢失了。
在这里插入图片描述
原因是什么?大家还记得文章上面在public/css目录下引入了一个bootstrap.css样式吗?若路由地址是"/xxx",那么在页面刷新的时候,会重新对所需的样式发起请求,地址如下:(正确的地址因为public目录是启动的服务器中内置的一个根目录,其下面的文件可以直接在URL中访问

http://localhost:3000/css/bootstrap.css

但是如果路由地址是"/xxx"/xxx,那么对应发起请求的地址是:(错误的地址

http://localhost:3000/xxx/css/bootstrap.css

也因此,发生了样式丢失的问题,解决方案1如下:修改index.html中的引入。

修改后:去掉 ./ 则代表去localhost:3000下的css目录下去寻找
<link rel="stylesheet" href="/css/bootstrap.css">
修改前:./ 代表以当前路径出发去寻找对应的路径
<link rel="stylesheet" href="./css/bootstrap.css">

解决方案2如下:

<link rel="stylesheet" href="%PUBLIC_URL%/css/bootstrap.css">

解决方案3如下:将BrowserRouter改为HashRouter
在这里插入图片描述
那么无论页面刷新多少次,样式都不会丢失。


对于以上案例,总结如下:

  1. public/index.html中引入样式的时候不写./ ,一般写/
  2. public/index.html中引入样式的时候不写./,一般写%PUBLIC_URL%
  3. 使用HashRouter

总结☆

根据以上内容,我们可以发现,React中使用路由的时候需要注意这么几个点:

  1. 通过< Route path="/demo" component={Demo} >来定义对应的路由应该渲染哪个组件。通过< Link to="/xxx"> 或者< NavLink to="/xxx">来定义路由。
  2. 最好在使用路由的时候,外层包一个Switch标签,保证路由的单一匹配。
  3. 对于index.html文件可能存在的样式丢失问题,要么就规范index.html文件中样式的引入地址,要么就用HashRouter来代替BrowserRouter

1.4 路由的模糊匹配和严格匹配

案例1:
在这里插入图片描述
页面中访问/home,看看是否能够匹配到:(可以
在这里插入图片描述

案例2:
在这里插入图片描述
页面中访问/home,看看是否能够匹配到:(不可以

在这里插入图片描述
从该两个案例中,我们发现,React在默认的情况下,支持模糊查询只要路由的前缀模糊匹配到了即可配对成功。


那么如何进行严格匹配呢?做出以下修改即可:(或者直接加上exact即可,后面的={true}可以去掉)
在这里插入图片描述
页面中访问/home,看看是否能够匹配到:(不可以
在这里插入图片描述
该小节做出以下总结:

  1. React路由默认使用的是模糊匹配。(顺序要一致)
  2. 开启严格匹配的方式:< Route exact path="/about" component={About} />
  3. 严格匹配不要随意开启,有些时候开启会导致二级路由无法匹配。

1.5 Redirect的使用

需求:页面打开的时候就默认匹配某个路由,然后渲染对应的组件。

方案:使用Redirect标签:

import { Route, Switch, Redirect } from 'react-router-dom'

<Switch>
  <Route path="/about" component={About} />
  <Route path="/home" component={Home} />
  <Redirect to="/about" />
</Switch>

当页面打开时:地址默认为/about,并且渲染对应组件内容。
在这里插入图片描述
注意

  • 一般Redirect写在所有路由注册的最下方,当所有路由都没有匹配到的时候,默认跳转Redirect指定的路由。

二. 嵌套路由

项目结构如下:
在这里插入图片描述
项目代码如下:(在原来的基础上新增两个子组件,处于Home组件下
Message组件:

import React, { Component } from 'react'

export default class Message extends Component {
    render() {
        return (
            <div>
                <ul>
                    <li>
                        <a href="/message1">message001</a>&nbsp;&nbsp;
                    </li>
                    <li>
                        <a href="/message2">message002</a>&nbsp;&nbsp;
                    </li>
                    <li>
                        <a href="/message/3">message003</a>&nbsp;&nbsp;
                    </li>
                </ul>
            </div>
        )
    }
}

News组件:

import React, { Component } from 'react'

export default class News extends Component {
    render() {
        return (
            <ul>
                <li>news001</li>
                <li>news002</li>
                <li>news003</li>
            </ul>
        )
    }
}

Home组件:

import React, { Component } from 'react'
import News from './News'
import Message from './Message'
import MyNavLink from '../../components/MyNavLink'
import { Route, Switch, Redirect } from 'react-router-dom'

export default class Home extends Component {
    render() {
        return (
            <div>
                <h3>Home</h3>
                <ul className="nav nav-tabs">
                    <li>
                        <MyNavLink to="/home/news">News</MyNavLink>
                    </li>
                    <li>
                        <MyNavLink to="/home/message">Message</MyNavLink>
                    </li>
                </ul>
                <Switch>
                	{/**注册子组件路由的时候,一定要写上父路由的path值 */}
                    <Route path="/home/news" component={News}></Route>
                    <Route path="/home/message" component={Message}></Route>
                    <Redirect to="/home/news" />
                </Switch>
            </div>
        )
    }
}

页面效果如下:
在这里插入图片描述
在这里插入图片描述

注意

  1. 至于子组件为何要跟上父组件的path值,因为倘若不跟,那么其本质上是和最顶层的父组件App下面定义的路由是同级关系,因此按照顺序进行路由匹配的时候,以/news为例,倘若找不到,就会根据Redirect指定的默认路由输出。那么这种情况,点击子导航News或者Message,最后页面呈现的都是About组件的内容。
  2. 路由匹配的时候,会先从父类组件开始匹配。按照顺序。

其实该章节本质上就需要大家知道一点即可:

  • React中若需要使用到嵌套路由,那么子组件中的路由前缀必须跟上父组件的路由。

2.1 向路由组件传递参数

2.1.1 传递params参数

希望在原本案例基础上再嵌套一层组件,效果如下:Detail组件的内容根据标签的不同来显示不同的数据,那么这种情况肯定就需要传递对应的参数。
在这里插入图片描述

Message组件下创建一个子组件Detail

import React, { Component } from 'react';

const DetailData = [
    { id: '01', content: 'Hello1' },
    { id: '02', content: 'Hello2' },
    { id: '03', content: 'Hello3' },
]

class Detail extends Component {
    render() {
        // 接收params参数
        const { id, title } = this.props.match.params
        // 通过Id去寻找对应的content内容
        const findResult = DetailData.find(dataObj => {
            return dataObj.id == id
        })
        return (
            <ul>
                <li>Id:{id}</li>
                <li>Title:{title}</li>
                <li>Content:{findResult.content}</li>
            </ul>
        );
    }
}
export default Detail;

Message组件:

import React, { Component } from 'react'
import Detail from './Detail'
import { Link, Route } from 'react-router-dom'

export default class Message extends Component {
    state = {
        messageArr: [
            { id: '01', title: '消息1' },
            { id: '02', title: '消息2' },
            { id: '03', 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 />
                {/**声明接收params参数,同时不要忘了加上Detail所有父组件的路由前缀 */}
                <Route path="/home/message/detail/:id/:title" component={Detail} />
            </div>
        )
    }
}

至于Detail组件中,为何params参数的接收时候通过this.props.match.params来获得呢?根据如下:(通过console.log(this.props.match.params)观察数据)
在这里插入图片描述
可见,React将路由的params参数都保存到props.match.params中了。

对应的URL地址:
在这里插入图片描述

总结1
  1. 路由的params参数指的是放在路由链接里面的参数,例如:
若参数是写死的:
<Link to='/home/message/detail/100'}>{msgObj.title}</Link>
若是动态的参数:需要加{},并且用``代替''
<Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>
  1. 注册路由(声明参数)的写法:< Route path="/home/message/detail/:id/:title" component={Detail} />,对应的参数通过:xxx的写法即可。
  2. 接收参数,通过this.props.match.params来获取。

2.1.2 传递search参数

改动如下:
Message组件中:

路由的声明:
{/**向路由组件传递params参数 */}
<Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp;
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
{/**向路由组件传递search参数 */}
<Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp;

路由的接收及匹配:
{/**声明接收params参数 */}
<Route path="/home/message/detail/:id/:title" component={Detail} />
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
{/**声明接收search参数,无需携带参数 */}
<Route path="/home/message/detail" component={Detail} />

Detail组件中:

const { id, title } = this.props.match.params
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
const { search } = this.props.location
// 因为这里获取到的search还带一个 ? ,所以需要通过slice方法来过滤第一个字符
import qs from 'querystring'
const { id, title } = qs.parse(search.slice(1))

证据如下:
在这里插入图片描述
对应的URL地址:
在这里插入图片描述

总结2
  1. 路由链接(携带参数):
<Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>
  1. 注册路由(无需声明参数,正常注册path即可):< Route path="/home/message/detail" component={Detail} />
  2. 接收参数通过this.props.location来获取。
  3. 但是获取到的search对象是urlencoded编码字符串,需要通过querystring来解析:
import qs from 'querystring'
const { id, title } = qs.parse(search.slice(1))

2.1.3 传递state参数

大家可以发现,上面两种传递参数的方式,其参数都会暴露到URL中,那么为了防止暴露,可以通过state来传递参数。
Message组件改动:

<Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp;
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
<Link to={{ pathname: '/home/message/detail', state: { id: msgObj.id, title: msgObj.title } }}>{msgObj.title}</Link>&nbsp;&nbsp;

对应的存储位置:
在这里插入图片描述
因此Detail组件改动:

const { id, title } = this.props.match.params
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
const { id, title } = this.props.location.state

那么此时URL地址为:可以发现URL地址中并不会暴露相关的参数。
在这里插入图片描述

总结3
  1. 路由链接(携带参数):
<Link to={{ pathname: '/home/message/detail', state: { id: msgObj.id, title: msgObj.title } }}>{msgObj.title}</Link>
  1. 注册路由(无需声明参数,正常注册path即可):< Route path="/home/message/detail" component={Detail} />
  2. 接收参数通过this.props.location.state来获取。
  3. 备注:URL中不会暴露对应的参数,并且哪怕页面刷新,状态也不会丢失。

2.2 push和replace

默认路由的跳转,使用的是push模式,也就是说,每次进行路由跳转的时候,都会留下痕迹。 即页面可以点击回退:
在这里插入图片描述
那么如何开启replace模式,即替换站点,不留痕迹呢?解决:在Linke标签中添加一个属性replace即可,如下:
在这里插入图片描述
验证如下:
点击消息1:
在这里插入图片描述
点击消息2:
在这里插入图片描述
点击页面回退:
在这里插入图片描述
此时页面展示为:
在这里插入图片描述
如果是push模式则:
在这里插入图片描述

2.2.1 编程式路由导航以及withRouter的使用

需求效果如下:
在这里插入图片描述
Message组件:(路由组件)

replaceShow = (id, title) => {
    // replace跳转
    this.props.history.replace(`/home/message/detail/${id}/${title}`)
}

pushShow = (id, title) => {
    // push跳转
    this.props.history.push(`/home/message/detail/${id}/${title}`)
}
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;
                                <button onClick={() => this.pushShow(msgObj.id, msgObj.title)}>push查看</button>&nbsp;&nbsp;
                                <button onClick={() => this.replaceShow(msgObj.id, msgObj.title)}>replace查看</button>&nbsp;&nbsp;
                            </li>
                        )
                    })
                }
            </ul>
            <hr />
            <Route path="/home/message/detail/:id/:title" component={Detail} />
        </div>
    )
}

Header组件:(一般组件)

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()
    }

    go = () => {
        this.props.history.go(2)
    }
    render() {
        return (
            <div className="page-header">
                <h2>React Router Demo</h2>
                <button onClick={this.back}>回退</button>
                <button onClick={this.forward}>前进</button>
                <button onClick={this.go}>go</button>
            </div>

        );
    }
}

export default withRouter (Header);

若页面效果呈现:

  1. 点击对应标签后的push查看按钮(页面留下访问痕迹),对应标签显示相应的内容。
  2. 点击Header组件中的goforwardback按钮分别会让页面前进至后2个历史记录、前进至后1个历史记录、倒退至上1个历史记录。

而诸如以下方式编程,就是所谓的编程式路由导航

pushShow = (id, title) => {
    // push跳转
    this.props.history.push(`/home/message/detail/${id}/${title}`)
}

还注意,Header身为一般组件,也就是说它并不具备路由组件应有的一些属性,比如操作this.props.history.goBack()以及相关的方法,那么怎么办?

可见代码中,对于Header这样的一般组件,引用了withRouter,并在最后暴露对象的时候,使用export default withRouter (Header);

作用:

  • withRouter可以加工一般组件,让一般组件具备路由组件所持有的API。
  • withRouter的返回值是一个新的组件,可以理解为将一般组件包装为路由组件。

2.3 BrowserRouter和HashRouter的区别

  1. 底层原理不一样:

BrowserRouter:使用H5的history API,不兼容IE9和以下版本。
HashRouter:使用的是URL的哈希值。

  1. URL表现形式不一样:

BrowserRouter:路径中没有#,例如localhost:3000/demo/test
HashRouter:路径中有#,例如localhost:3000/#demo/test

  1. 刷新后对路由state参数的影响:☆

BrowserRouter:没有任何影响,因为state保存在histroy对象中。
HashRouter:刷新后会导致路由state参数的丢失。

  1. HashRouter可以用于解决一些路径错误的相关问题。
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zong_0915

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值