zoukankan      html  css  js  c++  java
  • 从零开始的野路子React/Node(2)路由与页面跳转

    这两天主要摸索了一下React的路由做法,网上看了一些资料,但总觉得比较零散,所以自己稍微总结一下,好让自己明白一些。

    首先,对于一个稍微复杂一点的网站来说,一般都有多个页面,通常通过点击链接或者其他操作,我们可以在页面间跳转。而跳转的过程基本上就通过路由来实现。

    React的路由主要依靠react-router-dom这个库(当然,其他就算有我也不知道……)来实现。下面我们来看个简单的例子:

    1、准备各个页面

    我们假设我们需要三个页面(Home, Overview, Chapters),都在components目录下,各自的内容也非常简单。

    Home是个主页,我们放一些欢迎信息:

    import React from 'react';
    
    export default function Home() {
        return ( 
            <div>
                <h1>欢迎光临,随意挑选</h1>
            </div>
        );    
    }

    Overview是个概览页面:

    import React from 'react';
    
    export default function Overview() {
        return ( 
            <div>
                <h1>梗概</h1>
                <div>话说天下大势,分久必合,合久必分。</div>
            </div>
        );    
    }

    Chapters是个章节内容页面,看起来比较复杂,其实只是根据ChapDict的内容罗列第x章,以及对应的标题:

    import React from 'react';
    
    const ChapDict = {
        1:'宴桃园豪杰三结义 斩黄巾英雄首立功', 
        2:'张翼德怒鞭督邮 何国舅谋诛宦竖', 
        3:'议温明董卓叱丁原 馈金珠李肃说吕布', 
        4:'废汉帝陈留践位 谋董贼孟德献刀', 
        5:'未完待续'};
    
    export default function Chapters () {
        var chapnum = Object.keys(ChapDict)
    
        return (
            <div>
            {
                chapnum.map(
                    (item, idx) => (
                        <div>
                            <h2>第{ item }章</h2>
                            <p>{ ChapDict[item] }</p>
                        </div>
                    )
                ) 
            }
            </div>
        );  
    };

    接下来,我们把Home组件放到主文件App.js中,毕竟这是我们启动后第一眼就会看到的页面:

    import React from 'react';
    import './App.css';
    
    import Home from './components/Home';
    
    function App() {
      return (
        <div>
          <Home/>
        </div>
      );
    }
    
    export default App;

    通过npm install后npm start启动一下,我们可以看到一个极为粗放的主页:

    2、添加路由

    接下来,我们需要加入路由元素了。我们把三个页面组件都导入进来,并且从react-router-dom中导入BrowserRouter(名字太长,所以之后用Router代替)和Route。

    现在App.js变成了:

    import React from 'react';
    import './App.css';
    import { BrowserRouter as Router, Route } from 'react-router-dom';
    
    import Home from './components/Home';
    import Overview from './components/Overview';
    import Chapters from './components/Chapters';
    
    function App() {
      return (
        <div>
          <Router>
              <Route path='/' component={ Home }/> 
              <Route path='/overview' component={ Overview }/>
              <Route path='/chapters' component={ Chapters }/>
          </Router> 
        </div>
      );
    }
    
    export default App;

    每一条路由设置,我们都用Route来设定之,它有两个参数,分别是对应的URL地址(path)和对应调用的组件(component)。我们将其依次设定。最后把这几条路由都放在Router里面就行了。

    现在我们的主页看上去并没有什么变化,但是我们输入不同的URL已经能看到不同的内容了。但是有个问题是主页的内容为什么一直会显示呢?

    因为路由会逐条匹配,匹配到有对应的内容显示并继续向下再匹配。而我们的主页“/”永远会第一个被匹配到,所以永远会显示。解决的方法是:

    (1)path前加上exact,这样一来,一定要URL完全匹配为“/”才会显示主页,否则不会显示;

    (2)再加上Switch,Switch的作用是一旦匹配到一条就不再继续向下匹配了。

    所以我们把App.js改成:

    import React from 'react';
    import './App.css';
    import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
    
    import Home from './components/Home';
    import Overview from './components/Overview';
    import Chapters from './components/Chapters';
    
    function App() {
      return (
        <div>
          <Router>
            <Switch>
              <Route exact path='/' component={ Home }/> 
              <Route path='/overview' component={ Overview }/>
              <Route path='/chapters' component={ Chapters }/>
            </Switch>
          </Router> 
        </div>
      );
    }
    
    export default App;

    现在一切都正常多了:

    然而,还有个问题就是,如果用户输入了一个我们没有定义过的网址,比如http://localhost:3000/blahblah页面就没法正常显示,怎么办呢?我们可以通过Redirect把这些乱七八糟的输入都重定向到主页(自动跳回主页)。注意Redirect一定要放在最后!设定完from和to就大功告成了:

    import React from 'react';
    import './App.css';
    import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom';
    
    import Home from './components/Home';
    import Overview from './components/Overview';
    import Chapters from './components/Chapters';
    
    function App() {
      return (
        <div>
          <Router>
            <Switch>
              <Route exact path='/' component={ Home }/> 
              <Route path='/overview' component={ Overview }/>
              <Route path='/chapters' component={ Chapters }/>
              <Redirect from='/*' to='/'/>
            </Switch>
          </Router> 
        </div>
      );
    }
    
    export default App;

    3、来个导航栏吧

    到现在为止,我们已经可以通过输入不同的网址来访问不同的页面,但我们还没有做页面跳转。不如我们加个导航栏吧。我们在components目录下新建一个Navi组件:

    import React from 'react';
    import { Link } from 'react-router-dom';
    
    export default function Navi() {
        return ( 
            <div>
                <Link to='/'>
                    <p>首页</p>
                </Link>
    
                <Link to='/overview'>
                    <p>梗概</p>
                </Link>
    
                <Link to='/chapters'>
                    <p>章节</p>
                </Link>
            </div>
        );    
    }

    Navi的内容很简单,仅仅是三个段落:首页、梗概、章节而已,但是每个段落都被包含在Link当中,Link的作用就是跳转,我们设定了参数to就是需要跳转到的页面。接下来,我们需要把导航栏也加入到App.js中:

    import React from 'react';
    import './App.css';
    import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom';
    
    import Navi from './components/Navi';
    import Home from './components/Home';
    import Overview from './components/Overview';
    import Chapters from './components/Chapters';
    
    function App() {
      return (
        <div>
          <Router>
            <Navi/>
            <Switch>
              <Route exact path='/' component={ Home }/> 
              <Route path='/overview' component={ Overview }/>
              <Route path='/chapters' component={ Chapters }/>
              <Redirect from='/*' to='/'/>
            </Switch>
          </Router> 
        </div>
      );
    }
    
    export default App;

    由于导航栏每个页面都会出现,所以不需要添加路由,我们把它放在最前面,Switch之外就行了。再来看看:

    我们点击对应的部分就可以跳转到对应了页面啦~

    4、再增加点难度?

    以上都是静态的URL,要不我们试试动态的?比如每个章节都能点击,然后可以进入到那个章节的页面怎么样?

    我们先在components目录下做个Chap组件,这跟之前初体验中提到的方法一样,非常简单:

    import React from 'react';
    
    export default function Chap (props) {
    
        return (
            <div>
                <h2>第{ props.chap }章</h2>
                <p>{ props.title }</p>
            </div>
        );
    }

    props的chap属性决定显示第几章,而title属性决定显示什么标题。

    我们随便加个 <Chap chap='2' title='月明星稀,乌鹊南飞'/> 试试:

    红框部分就是Chap组件显示的内容。然后我们再加入一条路由通往Chap组件,这里注意Chapters对应的path前要加上exact防止提前被匹配掉:

    import React from 'react';
    import './App.css';
    import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom';
    
    import Navi from './components/Navi';
    import Home from './components/Home';
    import Overview from './components/Overview';
    import Chapters from './components/Chapters';
    import Chap from './components/Chap';
    
    function App() {
      return (
        <div>
          <Router>
            <Navi/>
            <Switch>
              <Route exact path='/' component={ Home }/> 
              <Route path='/overview' component={ Overview }/>
              <Route exact path='/chapters' component={ Chapters }/>
              <Route path='/chapters/:chap' component={ Chap }/>
              <Redirect from='/*' to='/'/>
            </Switch>
          </Router> 
        </div>
      );
    }
    
    export default App;

    好了,现在我们随便在”/chapters/”后面输个数字都会进入一个新的页面,但问题是还没有内容传入进去:

    这里我们要完成两个工作,一个是在Chapters中用Link做链接跳转。另一个则是通过Link传递对应的内容到Chap组件中进行显示。我们修改一下Chapters组件,加入Link,通过占位符来跳转到动态的地址:

    import React from 'react';
    import { Link } from 'react-router-dom';
    
    const ChapDict = {
        1:'宴桃园豪杰三结义 斩黄巾英雄首立功', 
        2:'张翼德怒鞭督邮 何国舅谋诛宦竖', 
        3:'议温明董卓叱丁原 馈金珠李肃说吕布', 
        4:'废汉帝陈留践位 谋董贼孟德献刀', 
        5:'未完待续'};
    
    export default function Chapters () {
        var chapnum = Object.keys(ChapDict)
    
        return (
            <div>
            {
                chapnum.map(
                    (item, idx) => (
                        <div>
                            <Link to={ `/chapters/${ item }` }>
                                <h2>第{ item }章</h2>
                            </Link>
                            <p>{ ChapDict[item] }</p>
                        </div>
                    )
                ) 
            }
            </div>
        );  
    };

    现在每个“第x章”上都有了链接,点击即可跳转到对应的页面” http://localhost:3000/chapters/x”,但依然没有内容。

    我们可以先修改一下Chap组件,我们把props.chap改为props.match.params.chap,这样可以匹配URL中的通配网址(还记得我们在Route中指定了Chap组件的path='/chapters/:chap'吗),这样chap的值就能被传入了:

    第x章有了,那么对应的标题呢?难道要复制一个ChapDict过来匹配吗?这样修改起来很不方便,而且不够偷懒。

    办法还是有的,我们分别修改一下Chapters组件里Link的参数,以及Chap组件中title的获取方式就行。

    import React from 'react';
    import { Link } from 'react-router-dom';
    
    const ChapDict = {
        1:'宴桃园豪杰三结义 斩黄巾英雄首立功', 
        2:'张翼德怒鞭督邮 何国舅谋诛宦竖', 
        3:'议温明董卓叱丁原 馈金珠李肃说吕布', 
        4:'废汉帝陈留践位 谋董贼孟德献刀', 
        5:'未完待续'};
    
    export default function Chapters () {
        var chapnum = Object.keys(ChapDict)
    
        return (
            <div>
            {
                chapnum.map(
                    (item, idx) => (
                        <div>
                            <Link to={{ 
                                pathname:`/chapters/${ item }`, 
                                query:{ title:ChapDict[item] }
                                }}>
                            <h2>第{ item }章</h2>
                            </Link>
                            <p>{ ChapDict[item] }</p>
                        </div>
                    )
                ) 
            }
            </div>
        );  
    };

    对于Chapters组件,我们修改了Link的to参数,它的内容变成了一个Object(类似python的dict),pathname即跳转的URL地址,而query则可以放置我们想要传递的内容。这里我们把title的内容传进去。

    再修改一下Chap组件:

    import React from 'react';
    
    export default function Chap (props) {
        let title = props.location.query !== undefined ? props.location.query.title : '未完待续'
    
        return (
            <div>
                <h2>第{ props.match.params.chap }章</h2>
                <p>{ title }</p>
            </div>
        );
    }

    我们通过props.location.query.title(而不是原来的props.title)来获取title的内容。

    需要注意的是,这里建立了一个临时变量title,并通过一个条件判断来获取值,这样做的原因是因为我们的ChapDict只有五个章节的内容,也就是说我们章节的URL只能支持到” http://localhost:3000/chapters/5”,如果用户输入一个” http://localhost:3000/chapters/36”怎么办?直接使用props.location.query.title的话会因为props.location.query是undefined而报错。因此我们加了一步条件判断,如果query是undefined的话,我们的标题就是“未完待续”。

      

    现在所有的内容都妥了~

    代码见:

    https://github.com/SilenceGTX/react_basic_route

  • 相关阅读:
    [水煮 ASP.NET Web API2 方法论](3-6)万能路由
    [水煮 ASP.NET Web API2 方法论](3-5)路由约束
    [水煮 ASP.NET Web API2 方法论](3-4)设置路由可选项
    [水煮 ASP.NET Web API2 方法论](3-3)路由默认值
    [水煮 ASP.NET Web API2 方法论](3-2)直接式路由/属性路由
    [转载自简书] ASPNetCore上传大文件碰到的一些问题总结
    [转载] 关于web.config
    [转载] sessionState 4种mode模式
    [转载] web.config 配置详解
    文档注释标记
  • 原文地址:https://www.cnblogs.com/silence-gtx/p/13251984.html
Copyright © 2011-2022 走看看