React——路由

路由

在最后有一个小项目,里面用到的知识点都在前面,最后附上了项目地址

知识点

Web分类

  • 静态页面:页面里的数据是写死的
  • 动态页面:页面里的数据是动态填充的
    • 后端渲染:数据在后端填充
    • 前端渲染:数据在前端填充

前端渲染是当客户端第一次访问网站的时候,就将该网站的所有数据全部传给客户端,当网站不同页面跳转的时候,并不需要再向后端发送请求
后端渲染则是一个网站的不同页面的切换都要向后端发送请求重新渲染
当一个网站的不同页面跳转的时候是相同的url,就是前端渲染的,使用Route也是前端渲染,但是会给每一个页面都唯一对应一个url,因为网站和应用不一样,很多应用可能需要某个功能的时候一层层点进去,但是网页可以直接通过某个链接直接进入到特定页面。
React——路由_第1张图片

安装环境

VSCODE安装插件:Auto Import - ES6, TS, JSX, TSX
安装Route组件:npm i react-router-dom

Route组件介绍

  • BrowserRouter:所有需要路由的组件,都要包裹在BrowserRouter组件内
  • Link:跳转到某个链接,to属性表示跳转到的链接
  • Routes:类似于C++中的switch,匹配第一个路径
  • Route:路由,path属性表示路径,element属性表示路由到的内容

URL中传递参数
解析URL:

<Route path="/linux/:chapter_id/:section_id/" element={<Linux />} />

获取参数,类组件写法:

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

class Linux extends Component {
    state = {  } 
    render() {
        console.log(this.props.params);
        return <h1>Linux</h1>;
    }
}

export default (props) => (
    <Linux
        {...props}
        params={useParams()}
    />
)
```函数组件写法:
```js
import React, { Component } from 'react';
import { useParams } from 'react-router-dom';

const Linux = () => {
    console.log(useParams());
    return (<h1>Linux</h1>);
}

export default Linux;

Search Params传递参数
类组件写法:

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

class Django extends Component {
    state = {
        searchParams: this.props.params[0],  // 获取某个参数
        setSearchParams: this.props.params[1],  // 设置链接中的参数,然后重新渲染当前页面
    }

    handleClick = () => {
        this.state.setSearchParams({
            name: "abc",
            age: 20,
        })
    }

    render() {
        console.log(this.state.searchParams.get('age'));
        return <h1 onClick={this.handleClick}>Django</h1>;
    }
}

export default (props) => (
    <Django
        {...props}
        params={useSearchParams()}
    />
);

函数组件写法:

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

const Django = () => {
    let [searchParams, setSearchParams] = useSearchParams();
    console.log(searchParams.get('age'));
    return (<h1>Django</h1>);
}

export default Django;

重定向
使用Navigate组件可以重定向。

<Route path="*" element={ <Navigate replace to="/404" /> } />

嵌套路由

<Route path="/web" element={<Web />}>
    <Route index path="a" element={<h1>a</h1>} />
    <Route index path="b" element={<h1>b</h1>} />
    <Route index path="c" element={<h1>c</h1>} />
</Route>

注意:需要在父组件中添加组件,用来填充子组件的内容。

新建一个项目叫route-app

  • src目录下,除了index.css和index.js,其余文件删除
  • 在src目录下新建一个components目录
  • 进入components目录新建一个app.jsx和navbar.jsx文件
  • navbar.jsx里面主要return一个导航栏组件,可以在bootstrap文档找一个,修改链接对应的url
  • app.js里面引入NavBar,return一个Navbar组件
  • 在index.js引入App组件,return 组件包裹在BrowserRouter内部
  • App是根组件

index.js

root.render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>
);

navbar.js

class NavBar extends Component {
    state = {  } 
    render() { 
        return (
            <nav class="navbar navbar-expand-lg navbar-light bg-light">
                <div class="container-fluid">
                    <a class="navbar-brand" href="/">讲义</a>
                    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                    </button>
                    <div class="collapse navbar-collapse" id="navbarNavAltMarkup">
                    <div class="navbar-nav">
                        <a class="nav-link active" aria-current="page" href="/">Home</a>
                        <a class="nav-link" href="/linux">Linux</a>
                        <a class="nav-link" href="/django">Django</a>
                        <a class="nav-link" href="/web">Web</a>
                    </div>
                    </div>
                </div>
            </nav>
        );
    }
}

app.js

class App extends Component {
    state = {  } 
    render() { 
        return (
            <React.Fragment>
                <NavBar />
            </React.Fragment>
        );
    }
}

初始页面实现如下:
React——路由_第2张图片
接下来,将Home Linux Django Web都做成一个组件

  • 在components目录下新建四个对应四个名字的.jsx文件和一个notFound.jsx文件(对应找不到页面404)
  • App是根组件,所以在app.js引入上面五个组件方便点击不同菜单时实现跳转,所有的组件要包裹在一个Routes组件下,五个组件分别在Route组件里作为element
  • 前面还是后端渲染,将之前导航栏组件里的链接标签a换成Link标签,再次切换不同页面,后端就不会每次重新加载了,即前端渲染

目录
React——路由_第3张图片
app.jsx

class App extends Component {
    state = {  } 
    render() { 
        return (
            <React.Fragment>
                <NavBar />
                <div className='container'>
                    <Routes>
                        <Route path="/" element={<Home />}/>
                        <Route path="/linux" element={<Linux />}/>
                        <Route path="/django" element={<Django />}/>
                        <Route path="/web" element={<Web />}/>
                    </Routes>
                </div>
            
            </React.Fragment>
        );
    }
}

navbar.jsx

class NavBar extends Component {
    state = {  } 
    render() { 
        return (
            <nav className="navbar navbar-expand-lg navbar-light bg-light">
                <div className="container-fluid">
                    <Link className="navbar-brand" to="/">讲义</Link>
                    <button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
                    <span className="navbar-toggler-icon"></span>
                    </button>
                    <div className="collapse navbar-collapse" id="navbarNavAltMarkup">
                    <div className="navbar-nav">
                        <Link className="nav-link active" to="/">Home</Link>
                        <Link className="nav-link" to="/linux">Linux</Link>
                        <Link className="nav-link" to="/django">Django</Link>
                        <Link className="nav-link" to="/web">Web</Link>
                    </div>
                    </div>
                </div>
            </nav>
        );
    }
}

实现web页面

  • 在web页面有五个讲义,在state里面定义讲义的id和title
  • 在render里面渲染,用map,每一个目录都放在Link里

web.jsx

class Web extends Component {
    state = { 
        webs : [
            {id: 0, title: 'HTML'},
            {id: 1, title: 'CSS'},
            {id: 2, title: 'JavaScript'},
            {id: 3, title: '拳皇'},
            {id: 4, title: 'React'},
        ]
     } 
    render() { 
        return (
            <React.Fragment>
                <h1>Web</h1>
                <hr />
                <div>
                    {this.state.webs.map(web => (
                        <div key={web.id}>
                            <Link to={`/web/content/${web.id}`}>{web.id +"."+web.title}</Link>
                        </div>
                    ))}
                </div>
            </React.Fragment>
        );
    }
}

已经有了连接,接下来要通过每个url里面的id去渲染对应的页面,因为一个网页可能有上万个目录,不可能写这么多路由,所以一般url最后的id会变成一个变量,所以要在URL里传递参数

  • 新建一个组件在webContent.jsx里,这个类组件接收URL传递的参数并显示
  • 在App组件里增加一个Route组件,element为webContent组件,用来通过传递参数

第一种,通过URL传递参数
webContent.jsx

class WebContent extends Component {
    state = {  } 
    render() { 
        <React.Fragment>
                <h1>Web - {this.props.params.chapter}</h1>
                <hr />
                <p>内容</p>
                <Link to="/web">返回</Link>
        </React.Fragment>
    }
}
 
export default (props) => (
    <WebContent
        {...props}
        params={useParams()}
    /> 
)

app.jsx

<Route path="/web/content/:chapter/" element={<WebContent />}/>

第二种:通过search Params传递参数

  • 修改web里面Link标签的URL书写格式,改为?形式
  • 修改app里面Route组件的path,匹配的部分保留,也就是问号前面的内容

web.jsx

<Link to={`/web/content?chapter=${web.id}`}>{web.id +"."+web.title}</Link>

app.jsx

<Route path="/web/content" element={<WebContent />}/>

webContent.jsx

class WebContent extends Component {
    state = {  
        searchParams : this.props.params[0],
        setSearchParams : this.props.params[1],
    }; 
    render() { 
        return (
            <React.Fragment>
                <h1>Web - {this.state.searchParams.get('chapter')}</h1>
                <hr />
                <p>内容</p>
                <Link to="/web">返回</Link>
            </React.Fragment>
        
        );
    }
}
 
export default (props) => (
    <WebContent
        {...props}
        params={useSearchParams()}
    /> 
)

当一个页面不存在的时候,重定向到404

  • 在app里面添加一个Route组件,element为NotFound组件
  • 同时在最后添加一个Route组件,path为*,可以匹配所有路径

app.jsx

<Route path="/404" element={<NotFound />} />
<Route path="*" element={ <Navigate replace to="/404" /> } />

有时候可能一个页面里面有很多子页面,上半部分是不变的,但是下半部分会通过不同的路由显示不同的内容,这个时候就用到了嵌套路由
比如Linux页面有两个嵌套路由homework和terminal

  • 在app里面的Linux对应的Route下面嵌套两个Route组件,但是这两个Route组件的path不用斜杠,直接写名字就行,会自动拼接到父组件的path下
  • 想要渲染出来,在父组件中添加组件,用来填充子组件的内容,即在Linux组件添加

app.js

<Route path="/linux" element={<Linux />}>
       <Route path="homework" element={<h4>homework的内容</h4>}></Route>
       <Route path="terminal" element={<h4>terminal的内容</h4>}></Route>
</Route>

linux.js

render() { 
        return (
            <React.Fragment>
                <h1>Linux</h1>
                <hr/>
                <Outlet />
            </React.Fragment>    
        );
}

学习网站ACwing
项目地址:GitCode

你可能感兴趣的:(React,react.js,javascript,前端)