学习ReactRouter路由的使用

 

参考官方文档:react-router官方文档

ReactRouter 是一种前端路由的实现方式,关于前端路由的原理后续补充

Router 的新版本号是 v5,ReactRouter 包含 3 个库:react-router、react-router-dom 和 react-router-native。

react-router 提供最基本的路由功能,实际使用时,我们不会直接安装 react-router,而是根据应用运行的环境选择安装 react-router-dom(在浏览器中使用)或 react-router-native(在 react-native 中使用)。react-router-dom 和 react-router-native 都依赖于 react-router,所以在安装时,react-router 也会自动安装。

注:react-router 依旧遵循一切皆组件的思想

在浏览器客户端中使用

1. 安装

yarn add react-router-dom

注:React Router v4+ 是对 React Router 的一次彻底重构,采用动态路由,遵循 React 中一切皆组件的思想,每一个 Route(路由)都是一个普通的 React 组件,所以 v4+ 版本不兼容之前的 ReactRouter 版本

2. 路由器

ReactRouter 通过 Router 和 Route 两个组件完成路由功能

所有的路由配置组件 Route 都定义为 Router 的子组件

在 Web 应用中,一般会使用对 Router 进行包装过的 BrowserRouter 或 HashRouter 两个组件

BrowserRouter 使用 HTML 5 的 history API(pushState、replaceState 等)实现应用的 UI 和 URL 的同步。

HashRouter 使用 URL 的 hash 实现应用的 UI 和 URL 的同步。

2.1 Router组件

Router 会创建一个 history 对象,history 用来跟踪 URL,当 URL 发生变化时,Router 的后代组件会重新渲染。

ReactRouter 中提供的其他组件可以通过 context 获取 history 对象,这也隐含说明了 ReactRouter 中的其他组件必须作为 Router 组件的后代组件使用。但 Router 中只能有唯一的一个子元素,这个组件可以是自定义的组件,或者第html 标签

// 正确  
ReactDOM.render(( 
 <BrowserRouter> 
    <App /> 
 </BrowserRouter>), document.getElementById('root'))  

// 错误,Router 中包含两个子元素
ReactDOM.render(( 
<BrowserRouter> 
    <App1 /> 
    <App2 /> 
</BrowserRouter> ),document.getElementById('root'))

3. 路由配置

Route 是使用频率最高的组件,每当有一个组件需要根据 URL 决定是否渲染时,就需要创建一个 Route,Route组件中几个常用属性:path 和 component 和 render,children,exact,同时, component 和 render, children属性 也是 Route渲染组件的方式,exact是路径的完全匹配和部分匹配

3.1 path 属性

用来配置路由跳转的路径

当 URL 匹配一个 Route 时,这个 Route 中定义的组件就会被渲染出来;

反之,Route 不进行渲染(Route 使用 children 属性渲染组件除外)

当使用 BrowserRouter 时,path 用来描述这个 Route 匹配的 URL 的 路径名字;

当使用 HashRouter 时,path 用来描述这个 Route 匹配的 URL 的 hash

3.2 component属性

用于渲染匹配上路径的组件

component 的值是一个组件,当 URL 和 Route 匹配时,component 属性定义的组件就会被渲染

<Route path='/foo' component={Foo}>

当URL="http://example.com/foo"时,Foo组件会被渲染

3.3 render属性

render的值是一个函数,可以传入一个props参数,这个函数返回一个React元素,它可以方便地为待渲染的组件传递额外的属性,同时它也可以为当前渲染的组件中再嵌套路由,也就是常说的二级,和三级 路由等

<Route path='/foo' render={(props) =>(       
   <Foo {...props} data={extraProps} />    
)}>

Foo 组件接收了一个额外的data属性

3.4 children属性

children的值也是一个函数,可以传入一个props参数,函数返回要渲染的React元素。与前两种方式不同之处是,无论是否匹配成功,children返回的组件都会被渲染

<Route path='/foo' children={(props) => (      
 <div>         
    <Foo />       
 </div>     
</Route>

3.5 match属性

当URL和Route匹配时,Route会创建一个match对象作为props中的一个属性传递给被渲染的组件,同时这个对象包含以下4个属性

(1)params:Route的path可以包含参数,例如<Routepath='/foo/:id'>包含一个参数id。params就是用于从匹配的URL中           解析出path中的参数,例如,当URL="http://example.com/foo/1"时,params ={id: 1}。

(2)isExact:是一个布尔值,当URL完全匹配时,值为true;当URL部分匹配时,值为false。例如,当path="/foo"、                 URL="http://example.com/foo"时,是完全匹配;当URL="http://example.com/ foo/1"时,是部分匹配。

(3)path:Route的path属性,构建嵌套路由时会使用到。

(4)url:URL的匹配部分

演示上边的属性用法,并将所有的路由抽离到一个路由文件中,进行统一管理所有的路由

1. 脚手架创建项目后的目录

安装路由

yarn add react-router-dom

App.js

import React from "react";

function App() {
  return (
    <div className="App">
      <header className="App-header">我是App组件</header>
    </div>
  );
}

export default App;

router.js(此文件为所有的路由配置文件,所有路由为同步加载)

import React from "react";

import { Route, BrowserRouter } from "react-router-dom";
// 引入组件
import App from "./App";
import SheQu from "./components/SheQu";
import Mine from "./components/Mine";
import News from "./components/News";
const AppRouter = () => (
  <BrowserRouter>
    <Route component={App} path="/" />
    <Route component={SheQu} path="/sq" />
    <Route component={Mine} path="/mine" />
    <Route component={News} path="/news" />
  </BrowserRouter>
);
export default AppRouter;

index.js

import React from "react";
import ReactDOM from "react-dom";
import AppRouter from "./router";
ReactDOM.render(<AppRouter />, document.getElementById("root"));

compoent文件夹的文件内容都一样

Mine.js,  News.js,   SheQu.js

import React, { Component } from "react";

export class Mine extends Component {
  render() {
    return <div>个人中心</div>;
  }
}

export default Mine;

启动项目

yarn start

可以看到,页面中已经显示出渲染的路由,默认渲染“/” , 即默认路径

再地址栏上手动修改路径,页面会进行改变,比如切换到 “/mine” 路径

然而问题来了, 不管你怎么切换后几个路径,App组件的内容都会渲染,这就需要使用Switch组件 和 Route 中的 exact 属性了

当URL和多个Route匹配时,这些Route都会执行渲染操作。如果只想让第一个匹配的Route渲染,那么可以把这些Route包到一个Switch组件中。如果想让URL和Route完全匹配时,Route才渲染,那么可以使用Route的exact属性,Switch和exact常常联合使用

修改router.js, 使用Switch 组件 和 exact

import React from "react";

import { Route, BrowserRouter, Switch } from "react-router-dom";
// 引入组件
import App from "./App";
import SheQu from "./components/SheQu";
import Mine from "./components/Mine";
import News from "./components/News";
const AppRouter = () => (
  <BrowserRouter>
    <Switch>
      <Route component={App} path="/" exact />
      <Route component={SheQu} path="/sq" />
      <Route component={Mine} path="/mine" />
      <Route component={News} path="/news" />
    </Switch>
  </BrowserRouter>
);
export default AppRouter;

此时再进行手动切换路径,就正常了

使用render函数 或者children函数 代替 component属性,下边这种写法依旧可以渲染

import React from "react";

import { Route, BrowserRouter, Switch } from "react-router-dom";
// 引入组件
import App from "./App";
import SheQu from "./components/SheQu";
import Mine from "./components/Mine";
import News from "./components/News";
const AppRouter = () => (
  <BrowserRouter>
    <Switch>
      {/* <Route children={() => <App />} path="/" exact /> */}
      <Route render={() => <App />} path="/" exact />
      <Route component={SheQu} path="/sq" />
      <Route component={Mine} path="/mine" />
      <Route component={News} path="/news" />
    </Switch>
  </BrowserRouter>
);
export default AppRouter;

4. 路由跳转

Link 和 NavLink 是React Router提供的链接组件,一个Link组件定义了当点击该Link时,页面应该如何路由

NavLink常用属性

activeClassName :  默认选中的路由的 class 名字

activeStyle: 默认选中的路由的样式,这是一个对象

to: 跳转到的路径

Link 属性:

to:string || Object     跳转的路径

修改App.js

import React, { Component } from "react";
import { Link } from "react-router-dom";
export class App extends Component {
  render() {
    return (
      <div>
        <ul>
          <li>
            <Link to="/news">新闻</Link>
          </li>
          <li>
            <Link to="/mine">我的</Link>
          </li>
          <li>
            <Link to="/sq">社区</Link>
          </li>
        </ul>
        {this.props.children}
      </div>
    );
  }
}

export default App;

修改router.js

import React from "react";

import { Route, BrowserRouter, Switch } from "react-router-dom";
// 引入组件
import App from "./App";
import SheQu from "./components/SheQu";
import Mine from "./components/Mine";
import News from "./components/News";

const AppRouter = () => (
  <BrowserRouter>
    <App>
      <Switch>
        <Route component={SheQu} path="/sq" exact />
        <Route component={Mine} path="/mine" />
        <Route component={News} path="/news" />
      </Switch>
    </App>
  </BrowserRouter>
);
export default AppRouter;

刷新页面,点击新闻,已经可以跳转了

使用 Redirect组件  进行重定向 默认 选中 新闻路由

import React from "react";

import { Route, BrowserRouter, Switch, Redirect } from "react-router-dom";
// 引入组件
import App from "./App";
import SheQu from "./components/SheQu";
import Mine from "./components/Mine";
import News from "./components/News";

const AppRouter = () => (
  <BrowserRouter>
    <App>
      <Switch>
        <Route component={SheQu} path="/sq" exact />
        <Route component={Mine} path="/mine" />
        <Route component={News} path="/news" />
        <Redirect to="/news" />
      </Switch>
    </App>
  </BrowserRouter>
);
export default AppRouter;

将地址栏的后边的路由清空,重新刷新,默认选中了 新闻 对应的组件

方法跳转

history.push() 以及 history.replace() 方法

修改App.js, 由于App 组件 并不是被当作路由组件,它只是一个包裹嵌套路由的容器,所以在这个组件中 没有 路由 的 history 对象,这就需要使用  withRouter 这个高阶组件把 组件 与 路由 绑定进来, 打印this.props 就可以拿到history 对象了, 

import React, { Component } from "react";
import { withRouter } from "react-router-dom";
export class App extends Component {
  render() {
    console.log(this.props);
    const { history, children } = this.props;
    return (
      <div>
        <ul>
          <li
            onClick={() => {
              history.push("/news");
            }}
          >
            新闻
          </li>
          <li
            onClick={() => {
              history.push("/mine");
            }}
          >
            我的
          </li>
          <li
            onClick={() => {
              history.push("/sq");
            }}
          >
            社区
          </li>
        </ul>
        {children}
      </div>
    );
  }
}

export default withRouter(App);

清空, 刷新后,点击,路由继续跳转了。

5. 关于 404 页面 , 直接添加一个组件,不带任何路径就行   <Route component={NoMatch} />

import React from "react";

import { Route, BrowserRouter, Switch, Redirect } from "react-router-dom";
// 引入组件
import App from "./App";
import SheQu from "./components/SheQu";
import Mine from "./components/Mine";
import News from "./components/News";
import NoMatch from "./components/AppChild";
const AppRouter = () => (
  <BrowserRouter>
    <App>
      <Switch>
        <Route render={() => <SheQu />} path="/sq" exact />
        <Route component={Mine} path="/mine" />
        <Route component={News} path="/news" />
        <Route component={NoMatch} />
        <Redirect to="/news" />
      </Switch>
    </App>
  </BrowserRouter>
);
export default AppRouter;

6. 路由传参

App.js

history.push("/news?id=10");

import React, { Component } from "react";
import { withRouter, Link } from "react-router-dom";
export class App extends Component {
  render() {
    const { history, children } = this.props;
    return (
      <div>
        <ul>
          <li
            onClick={() => {
              history.push("/news?id=10");
            }}
          >
            新闻
          </li>
          <li>
            <Link to="/mine/10"> 我的</Link>
          </li>
          <li
            onClick={() => {
              history.push("/sq");
            }}
          >
            社区
          </li>
        </ul>
        {children}
      </div>
    );
  }
}

export default withRouter(App);

News.js

import React, { Component } from "react";
export class News extends Component {
  render() {
    console.log(this.props);
    return <div>我是news 新闻</div>;
  }
}
export default News;

再 location 中 获取参数,关于动态路由,看官方例子,以下不做赘述


整合路由的一些知识,来个项目实站练习

首页,新闻,社区,我的,404页面,新闻详情页面, 目录如下

index.js

import React from "react";
import ReactDOM from "react-dom";
import AppRouter from "./router";
ReactDOM.render(<AppRouter />, document.getElementById("root"));

App.js

import React, { Component } from "react";
import { withRouter } from "react-router-dom";
import "./css/app.css";
export class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      navList: [
        {
          id: 1,
          name: "首页",
          path: "/"
        },
        {
          id: 2,
          name: "新闻",
          path: "/news"
        },
        {
          id: 3,
          name: "社区",
          path: "/sq"
        },
        {
          id: 4,
          name: "我的",
          path: "/mine"
        }
      ]
    };
  }
  render() {
    const { children } = this.props;
    const { navList } = this.state;
    return (
      <div className="app">
        <ul>
          {navList.map(item => (
            <li
              key={item.id}
              onClick={() => this.props.history.push(item.path)}
            >
              {item.name}
            </li>
          ))}
        </ul>
        <div>{children}</div>
      </div>
    );
  }
}

export default withRouter(App);

app.css

body {
    margin: 0;
    padding: 0;
}

.app ul {
    display: flex;
    margin: 0;
    background-color: #ccc;
}

.app ul li {
    list-style: none;
    padding: 10px;
    cursor: pointer;
}

.News {
    display: flex;
}

.news {
    display: block !important;
    background-color: #fff !important;
    border: 1px solid #666;
    width: 400px;
    margin: 10px !important;
}

.newsInfor {
    width: 500px;
    background-color: #eee;
    height: 300px;
}

components文件夹下

Home.js, MIne.js, SheQu.js, 内容自己改改啊,都一样


export class Home extends Component {
  render() {
    return <div>我是首页</div>;
  }
}

export default Home;

router.js

import React from "react";

import { Route, BrowserRouter, Switch } from "react-router-dom";
// 引入组件
import App from "./App";
import SheQu from "./components/SheQu";
import Home from "./components/Home";
import Mine from "./components/Mine";
import News from "./components/News";
import NoMatch from "./components/NoMatch";
const AppRouter = () => (
  <BrowserRouter>
    <App>
      <Switch>
        <Route component={Home} path="/" exact />
        <Route component={Mine} path="/mine" />
        <Route component={News} path="/news" />
        <Route component={SheQu} path="/sq" />
        <Route component={NoMatch} />
      </Switch>
    </App>
  </BrowserRouter>
);
export default AppRouter;

News.js

import React, { Component } from "react";

export class News extends Component {
  constructor(props) {
    super(props);
    this.state = {
      newsList: [
        {
          id: 1,
          title: "hello , im in the world1 ?"
        },
        {
          id: 2,
          title: "hello , im in the world2 , you are OK ?"
        },
        {
          id: 3,
          title: "hello , im in the world3, China is Good ? "
        },
        {
          id: 4,
          title: "hello , im in the world4 ,english is bad?"
        }
      ]
    };
  }
  itemHandle(id) {
    
  }
  render() {
    return (
      <div className="News">
        <ul className="news">
          {this.state.newsList.map(item => (
            <li key={item.id} onClick={() => this.itemHandle(item.id)}>
              {item.title}
            </li>
          ))}
        </ul>
        <div className="newsInfor">{this.props.children}</div>
      </div>
    );
  }
}

export default News;

启动服务,点击新闻,首页,等切换一下

点击新闻列表,展示新闻详情

添加newsInfor.js

import React, { Component } from "react";

export class newsInfor extends Component {
  constructor(props) {
    super(props);
    this.state = {
      newsInforList: [
        {
          id: 1,
          infor: "我是第一个hello world"
        },
        {
          id: 2,
          infor: "我是第二个hello world"
        },
        {
          id: 3,
          infor: "我是第三个hello world"
        },
        {
          id: 4,
          infor: "我是第四个hello world"
        }
      ]
    };
  }
  filterNews() {
    let id = this.props.match.params.id;
    const { newsInforList } = this.state;
    return newsInforList.filter(item => {
      return item.id === Number(id);
    });
  }
  render() {
    return (
      <div>
        {this.filterNews().map(item => (
          <p key={item.id}>{item.infor}</p>
        ))}
      </div>
    );
  }
}

export default newsInfor;

修改router.js

import React from "react";

import { Route, BrowserRouter, Switch } from "react-router-dom";
// 引入组件
import App from "./App";
import SheQu from "./components/SheQu";
import Home from "./components/Home";
import Mine from "./components/Mine";
import News from "./components/News";
import NoMatch from "./components/NoMatch";
import newsInfor from "./components/newsInfor";
const AppRouter = () => (
  <BrowserRouter>
    <App>
      <Switch>
        <Route component={Home} path="/" exact />
        <Route component={Mine} path="/mine" />
        <Route component={News} path="/news" />
        <Route component={newsInfor} path="/newsInfor/:id" />
        <Route component={SheQu} path="/sq" />
        <Route component={NoMatch} />
      </Switch>
    </App>
  </BrowserRouter>
);
export default AppRouter;

News.js 中补全 事件回调函数

import React, { Component } from "react";

export class News extends Component {
  constructor(props) {
    super(props);
    this.state = {
      newsList: [
        {
          id: 1,
          title: "hello , im in the world1 ?"
        },
        {
          id: 2,
          title: "hello , im in the world2 , you are OK ?"
        },
        {
          id: 3,
          title: "hello , im in the world3, China is Good ? "
        },
        {
          id: 4,
          title: "hello , im in the world4 ,english is bad?"
        }
      ]
    };
  }
  itemHandle(id) {
    this.props.history.push(`/newsInfor/` + id);
  }
  render() {
    return (
      <div className="News">
        <ul className="news">
          {this.state.newsList.map(item => (
            <li key={item.id} onClick={() => this.itemHandle(item.id)}>
              {item.title}
            </li>
          ))}
        </ul>
        <div className="newsInfor">{this.props.children}</div>
      </div>
    );
  }
}

export default News;

点击跳转, 可以看到拿到新闻详情数据了

进行路由嵌套

修改router.js

import React from "react";

import { Route, BrowserRouter, Switch } from "react-router-dom";
// 引入组件
import App from "./App";
import SheQu from "./components/SheQu";
import Home from "./components/Home";
import Mine from "./components/Mine";
import News from "./components/News";
import NoMatch from "./components/NoMatch";
import newsInfor from "./components/newsInfor";
const AppRouter = () => (
  <BrowserRouter>
    <App>
      <Switch>
        <Route component={Home} path="/" exact />
        <Route component={Mine} path="/mine" />
        <Route
          render={props => (
            <News {...props}>
              <Route path="/news/newsInfor/:id" component={newsInfor} />
            </News>
          )}
          path="/news"
        />
        <Route component={SheQu} path="/sq" />
        <Route component={NoMatch} />
      </Switch>
    </App>
  </BrowserRouter>
);
export default AppRouter;

修改News.js

import React, { Component } from "react";

export class News extends Component {
  constructor(props) {
    super(props);
    this.state = {
      newsList: [
        {
          id: 1,
          title: "hello , im in the world1 ?"
        },
        {
          id: 2,
          title: "hello , im in the world2 , you are OK ?"
        },
        {
          id: 3,
          title: "hello , im in the world3, China is Good ? "
        },
        {
          id: 4,
          title: "hello , im in the world4 ,english is bad?"
        }
      ]
    };
  }
  itemHandle(id) {
    this.props.history.push(`/news/newsInfor/` + id);
  }
  componentDidMount() {
    this.props.history.push(`/news/newsInfor/` + this.state.newsList[0].id);
  }
  render() {
    return (
      <div className="News">
        <ul className="news">
          {this.state.newsList.map(item => (
            <li key={item.id} onClick={() => this.itemHandle(item.id)}>
              {item.title}
            </li>
          ))}
        </ul>
        <div className="newsInfor">{this.props.children}</div>
      </div>
    );
  }
}

export default News;

实战2 , 处理是否登录了,来决定路由的展示

Login.js

import React, { Component } from "react";

export class Login extends Component {
  render() {
    return (
      <div className="login">
        <input type="text" />
        <br />
        <input type="password" />
        <br />
        <button onClick={this.login}>登录</button>
      </div>
    );
  }
  login = () => {
    //   存储登录标志
    localStorage.setItem("isLogin", true);
    this.props.history.push("/app");
  };
}

export default Login;

router.js

当然你也可以再路由这里通过三木运算,判断,如果等过了,直接进来,如果没有,重定向到登录页面

import React from "react";

import { Route, BrowserRouter, Switch, Redirect } from "react-router-dom";
// 引入组件
import App from "./App";
import SheQu from "./components/SheQu";
import Home from "./components/Home";
import Mine from "./components/Mine";
import News from "./components/News";
import NoMatch from "./components/NoMatch";
import newsInfor from "./components/newsInfor";
import Login from "./components/Login";
const AppRouter = () => (
  <BrowserRouter>
    <Switch>
      <Route component={Login} path="/" exact />
      <Route
        path="/app"
        render={props => (
          <App {...props}>
            <Switch>
              <Route component={Home} path="/app/home" />
              <Route component={Mine} path="/app/mine" />
              <Route
                render={props => (
                  <News {...props}>
                    <Route
                      path="/app/news/newsInfor/:id"
                      component={newsInfor}
                    />
                  </News>
                )}
                path="/app/news"
              />
              <Route component={SheQu} path="/app/sq" />
              <Route component={NoMatch} />
            </Switch>
          </App>
        )}
      />
    </Switch>
  </BrowserRouter>
);
export default AppRouter;

News.js

import React, { Component } from "react";

export class News extends Component {
  constructor(props) {
    super(props);
    this.state = {
      newsList: [
        {
          id: 1,
          title: "hello , im in the world1 ?"
        },
        {
          id: 2,
          title: "hello , im in the world2 , you are OK ?"
        },
        {
          id: 3,
          title: "hello , im in the world3, China is Good ? "
        },
        {
          id: 4,
          title: "hello , im in the world4 ,english is bad?"
        }
      ]
    };
  }
  itemHandle(id) {
    this.props.history.push(`/app/news/newsInfor/` + id);
  }

  render() {
    return (
      <div className="News">
        <ul className="news">
          {this.state.newsList.map(item => (
            <li key={item.id} onClick={() => this.itemHandle(item.id)}>
              {item.title}
            </li>
          ))}
        </ul>
        <div className="newsInfor">{this.props.children}</div>
      </div>
    );
  }
}

export default News;

App.js

import React, { Component } from "react";
import { withRouter } from "react-router-dom";
import "./css/app.css";
export class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      navList: [
        {
          id: 1,
          name: "首页",
          path: "/app/home"
        },
        {
          id: 2,
          name: "新闻",
          path: "/app/news"
        },
        {
          id: 3,
          name: "社区",
          path: "/app/sq"
        },
        {
          id: 4,
          name: "我的",
          path: "/app/mine"
        }
      ]
    };
  }
  componentDidMount() {
    // 获取是否登录的标志
    const { history } = this.props;
    let islogin = localStorage.getItem("isLogin");
    if (islogin) {
      history.push("/app/home");
    } else {
      history.push("/");
    }
  }
  render() {
    const { children } = this.props;
    const { navList } = this.state;
    return (
      <div className="app">
        <ul>
          {navList.map(item => (
            <li
              key={item.id}
              onClick={() => this.props.history.push(item.path)}
            >
              {item.name}
            </li>
          ))}
        </ul>
        <div>{children}</div>
      </div>
    );
  }
}

export default withRouter(App);

app.css

body {
    margin: 0;
    padding: 0;
}

.app ul {
    display: flex;
    margin: 0;
    background-color: #ccc;
}

.app ul li {
    list-style: none;
    padding: 10px;
    cursor: pointer;
}

.News {
    display: flex;
}

.news {
    display: block !important;
    background-color: #fff !important;
    border: 1px solid #666;
    width: 400px;
    margin: 10px !important;
}

.newsInfor {
    width: 500px;
    background-color: #eee;
    height: 300px;
}

.login {
    margin: 300px;
}

点击刷新跳转吧

总结: 当配合react 路由 进行开发时, 你可以先画一个草图,自己过一下流程图, 然后再设计路由,这样会很好理解,思路清晰一些,每个人路由设计的不一样,具体写法也不一样

 

 

 

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值