嵌套路由,从广义上来说,分为两种情况:一种是每个路由到的组件都有共有的内容,这时把共有的内容抽离成一个组件,变化的内容也是一个组件,两种组件组合嵌套,形成一个新的组件。另一种是子路由,路由到的组件内部还有路由。

  对于共有的内容,典型的代表就是网页的侧边栏,假设侧边栏在左边,我们点击其中的按钮时,右侧的内容会变化,但不管右侧的内容怎么变化,左侧的侧边栏始终存在。这个侧边栏就是共有内容,如下图所示

  这个共有内容要怎么处理? 首先想到的就是把这个功能提取出来,写成一个组件,然后再把这个组件依次应用到其它路由组件,如about, products 等。导航栏肯定是一个导航,不过这里我们要使用navLink 组件,因为从图片中可以看到它有高亮显示,我们要设计一个高亮显示的样式。新建一个menus.js 文件,来写这个导航组件

import React from 'react'
// 引入NavLink 组件
import { NavLink } from "react-router-dom";
import './menus.css' // 高亮的样式,表示我们在哪个导航下
const selectedStyle = {
backgroundColor: 'white',
color: 'slategray'
} // navLink, activeStyle 点击高亮显示当前标签。
export const MainMenu = () => (
<nav className='main-menu'>
<NavLink to='/'>首页</NavLink>
<NavLink to='/about' activeStyle = {selectedStyle}>关于我们</NavLink>
<NavLink to='/events' activeStyle = {selectedStyle}>企业事件</NavLink>
<NavLink to='/products' activeStyle = {selectedStyle}>公司产品</NavLink>
<NavLink to='/contact' activeStyle = {selectedStyle}>联系我们</NavLink>
</nav>
)

  可以看到导航的高亮样式可以在NavLink 组件中直接设置,这也是Link 和NavLink的区别。这里还写了一点样式,在menus.css 文件中。

/* 页面左侧主要导航 */
.main-menu {
display: flex;
flex-direction: column;
height: 100%;
width: 20%;
min-width: 20%;
background-color: slategray;
color: ghostwhite;
} .main-menu a {
color: ghostwhite;
text-align: center;
padding: 1em;
font-size: 1.5em;
}

  按照上面的说法,我们把这个组件应用到其它组件中,在pages.js中引入该组件,并修改Events,Products,

Contact和 About 组件中,引入的组件命名为MainMenu
// 企业事件内容
export const Events = () => (
<div>
<MainMenu></MainMenu>
<section className="events">
<h1>企业大事件</h1>
</section>
</div>
) // 公司产品
export const Products = () => (
<div>
<MainMenu></MainMenu>
<section className="products">
<h1>公司产品:主要经营 手机、电脑</h1>
</section>
</div>
) // 联系我们
export const Contact = () => (
<div>
<MainMenu></MainMenu>
<section className="contact">
<h1>联系我们</h1>
<p>公司电话:0755 - 12345678</p>
</section>
</div>
)

  这时你会发现,相同的代码复制了4遍,还可以接受,毕竟只有一个共有组件。但如果about, home 这些组件有好多共有的部分,我们这样一遍一遍的复制就有点麻烦了。所以还要对page.js文件这些组件相同的内容进行进一步的抽取。抽取的形式应该是

<div>
<MainMenu></MainMenu>
// 变化的部分
</div>

  现在最主要的部分就是这些变化的部分要怎么处理,想到了其实也很简单,因为React 有一个children 属性, 直接把这些变化的部分写成props.childern 就可以了。这时你会发现,这个抽取的组件像一个布局模板, 比如单页面应用时的页眉和页脚这些共有的部分,也可以放到这个模版中。新建一个template.js 文件

import React from 'react'
import { MainMenu } from "./menus"; export const Template = (props) => (
<div className = 'page'>
<MainMenu></MainMenu>
{props.children}
</div>
)

  上面的代码中加了一个样式类page, 在pages.css 中添加一个 page样式,

.page {
display: flex;
justify-content: space-between;
height: 100%;
margin-top: 20px;
}

  现在再在pages.js中的相应组件中应用Template组件

import { Template } from "./template";// 企业事件内容
export const Events = () => (
<Template>
<section className="events">
<h1>企业大事件</h1>
</section>
</Template> ) // 公司产品
export const Products = () => (
<Template>
<section className="products">
<h1>公司产品:主要经营 手机、电脑</h1>
</section>
</Template>
) // 联系我们
export const Contact = () => (
<Template>
<section className="contact">
<h1>联系我们</h1>
<p>公司电话:0755 - 12345678</p>
</section>
</Template>
)

  这时效果就达到了,左侧的侧边栏始终存在。现在 我们再来实现一下子路由。

  子路由: 就是当路由匹配成功后,它会渲染出一个组件。这个组件中还有路由,这个路由就是子路由。比如: 我进入到about页面,about 组件渲染出来,而about 组件中,还有history, service 要展示,它还需要路由,about 组件中的路由就是子路由,如下图所示

  about组件上面的导航条,我们还是使用NavLink实现,导航条下面的内容肯定是路由系统。对于这里的路由来说,我们要注意的就是它的path属性,因为它是子路由,我们首先要进入到父组件about下面,才能显示这个路由系统,所以它前面的路径都要加about, 匹配公司服务, 它的path 肯定是’/about/service’; 其它三个对应的则是 about/company,  about/location, about/history, 但如果四个路由都这么匹配,就会出现一个问题,首次进入到about 组件时,它什么都不会显示。就是说,我们点击左侧的侧边栏中的 ‘关于我们’,它不会显示任何内容。这里可以这么处理,点击 ‘关于我们’,它肯定会显示四个子路由中的 一个,比如显示公司简介, 我们就可以把公司简介的路由直接设置成about, 对于子路由来说,父路由进来显示的默认页面,就可以设置和父路由一样。

  导航条,我们写到menus.js 文件里面,命名为AboutMenu

export const AboutMenu = () => (
<ul className="about-menu">
<li>
<NavLink to='/about' exact activeStyle ={selectedStyle}>公司简介</NavLink>
</li>
<li>
<NavLink to='/about/history' activeStyle ={selectedStyle}>公司历史</NavLink>
</li>
<li>
<NavLink to='/about/services' activeStyle ={selectedStyle}>公司服务</NavLink>
</li>
<li>
<NavLink to='/about/location' activeStyle ={selectedStyle}>企业位置</NavLink>
</li>
</ul>
)

  我们再在pages.js中修改about组件的内容,使其包含路由组件

export const About = () => (
<Template>
<section className="about">
<AboutMenu></AboutMenu>
<Route path='/about' exact component={Company}/>
<Route path='/about/history' component={History}/>
<Route path='/about/services' component={Services}/>
<Route path='/about/location' component={Location}/>
</section>
</Template>
)

  同时再简单地定义Company, History 等4个显示组件。

export const Services = () => (
<section>
<p>公司服务</p>
</section>
) export const Location = () => (
<section>
<p>公司位置</p>
</section>
) export const Company = () => (
<section>
<p>公司简介</p>
</section>
) export const History = () => (
<section>
<p>公司历史</p>
</section>
)

  这时就实现了子路由的功能。

  动态路由:就是在匹配路径path 的后面加上冒号 + 参数, 如path ="products/:id". 比如我们进入产品页面,它有手机,电脑等产品,我们点击单个产品,肯定进入到产品详情页面,我们为每一个产品都建一个产品详情组件,有点不太现实,因为产品太多,写的大累,再说,产品种类是动态增加的,增加一个产品,就增加一个组件,维护起来也太累。最好的办法就是,它们都跳转到一个详情组件,根据不同的产品渲染动态渲染不同的内容, 那么产品详情组件就要接受一个参数表示产品类型,这个类型是动态的,所以要用一个变量,路由的格式就是details/:type, 那组件内部怎么得到这个参数呢,我们之前说过,当渲染组件时,路由会给我们组件注入3个参数,这里使用match 就可以了,它有一个params属性,就是专门获取动态路由参数的。

  我们在products组件内部,写两个link, 用于导航到产品详情,同时写一个产品详情页组件。

// 公司产品
export const Products = () => (
<Template>
<section className="products">
<Link to='/details/telphone'>手机</Link>
&nbsp;
<Link to='/details/computer'>电脑</Link>
</section>
</Template>
) // 产品详情组件
export const Details = (props) => {
console.log(props.match.params);
return <p>这是 {props.match.params.type}详情内容</p>
}

  但产品详情的路由的定义要放到什么地方呢?由于产品详情要占据整个页面,它和 Events, Products 组件是一个级别的,所以要放到App组件 中, 在app.js文件中路由下面增加一条路由,<Route path='/details/:type' component={Details}></Route>

<Switch>
<Route path='/' exact component={Home}/>
<Route path='/about' component={About}/>
<Route path='/contact' component={Contact}/>
<Route path='/products' component={Products}/>
<Route path='/events' component={Events}/>
<Route path='/details/:type' component={Details}></Route>
<Route component={NotFound404}/>
</Switch>

  现在可以实现动态路由了。

  最后一点是重定向路由组件<Redirect>, 它最基本使用就是一个to 属性,和link的to 属性一个意思,到什么地方去。<Redirect to=’/about’>, 就是重定向到about组件。当在Switch 组件下面,它还有一个from属性,它的接受的参数和to 一样,是一个路径,表示从哪里来。在这里,假设用户在浏览器地址栏中输入history, 我们把它重定向about/history, 就可以这么写

<Redirect from='/history' to='about/history'></Redirect>

  它还有一种使用场景就是,已有路径的重定向,比如,当用户访问首页的时候,把它重定向到产品页面。这里要知道的是,Route 组件的除了接受component,还可以接受一个render 函数,render函数渲染出一个组件。

<Route path='/' exact render={() => <Redirect to='/products' />} />

  整个项目内容如下,就是在src目录下新建了 menus.js, pages.js, template.js,pages.css, menus.css 文件,修改了App.js 文件

  App.js

import React from 'react'
import { HashRouter, Route, Switch, Redirect } from 'react-router-dom' // 引入展示组件
import { About, Contact, Home, Products, Events, NotFound404, Details } from './pages'; function App() {
return (
<HashRouter>
<div>
<Switch>
<Route path='/' exact component={Home}/>
<Route path='/about' component={About}/>
<Route path='/contact' component={Contact}/>
<Route path='/products' component={Products}/>
<Route path='/events' component={Events}/>
<Redirect from='/history' to='about/history'></Redirect>
<Route path='/details/:type' component={Details}></Route>
<Route component={NotFound404}/>
</Switch>
</div>
</HashRouter>
)
} export default App

  menus.js

import React from 'react'
// 引入NavLink 组件
import { NavLink } from "react-router-dom";
import './menus.css' // 高亮的样式,表示我们在哪个导航下
const selectedStyle = {
backgroundColor: 'white',
color: 'slategray'
} // navLink, activeStyle 点击高亮显示当前标签。
export const MainMenu = () => (
<nav className='main-menu'>
<NavLink to='/'>首页</NavLink>
<NavLink to='/about' activeStyle = {selectedStyle}>关于我们</NavLink>
<NavLink to='/events' activeStyle = {selectedStyle}>企业事件</NavLink>
<NavLink to='/products' activeStyle = {selectedStyle}>公司产品</NavLink>
<NavLink to='/contact' activeStyle = {selectedStyle}>联系我们</NavLink>
</nav>
) export const AboutMenu = () => (
<ul className="about-menu">
<li>
<NavLink to='/about' exact activeStyle ={selectedStyle}>公司简介</NavLink>
</li>
<li>
<NavLink to='/about/history' activeStyle ={selectedStyle}>公司历史</NavLink>
</li>
<li>
<NavLink to='/about/services' activeStyle ={selectedStyle}>公司服务</NavLink>
</li>
<li>
<NavLink to='/about/location' activeStyle ={selectedStyle}>企业位置</NavLink>
</li>
</ul>
)

  pages.js

import React from 'react'
import { Link, Route } from "react-router-dom"; import './pages.css';
import { Template } from "./template";
import { AboutMenu } from "./menus";
// 首页内容
export const Home = () => (
<section className="home">
<h1>企业网站</h1>
<nav>
{/* 添加了四个导航组件Link */}
<Link to='/about'>关于我们</Link>
<Link to='/events'>企业事件</Link>
<Link to='/products'>公司产品</Link>
<Link to='/contact'>联系我们</Link>
</nav>
</section>
) // 企业事件内容
export const Events = () => (
<Template>
<section className="events">
<h1>企业大事件</h1>
</section>
</Template> ) // 公司产品
export const Products = () => (
<Template>
<section className="products">
<Link to='/details/telphone'>手机</Link>
&nbsp;
<Link to='/details/computer'>电脑</Link>
</section>
</Template>
) // 产品详情组件
export const Details = (props) => {
console.log(props.match.params);
return <p>这是 {props.match.params.type}详情内容</p>
} // 联系我们
export const Contact = () => (
<Template>
<section className="contact">
<h1>联系我们</h1>
<p>公司电话:0755 - 12345678</p>
</section>
</Template>
) // 关于我们
export const About = () => (
<Template>
<section className="about">
<AboutMenu></AboutMenu>
<Route path='/about' exact component={Company}/>
<Route path='/about/history' component={History}/>
<Route path='/about/services' component={Services}/>
<Route path='/about/location' component={Location}/>
</section>
</Template>
)
// 没有匹配成功的404组件
export const NotFound404 = (props) => (
<div className="whoops-404">
<h1>没有页面可以匹配</h1>
</div>
) // 4个子路由对应的显示组件
const Services = () => (
<section>
<p>公司服务</p>
</section>
) const Location = () => (
<section>
<p>公司位置</p>
</section>
) const Company = () => (
<section>
<p>公司简介</p>
</section>
) const History = () => (
<section>
<p>公司历史</p>
</section>
)

  template.js

import React from 'react'
import { MainMenu } from "./menus"; export const Template = (props) => (
<div className = 'page'>
<MainMenu></MainMenu>
{props.children}
</div>
)

  menus.css

/* 页面左侧主要导航 */
.main-menu {
display: flex;
flex-direction: column;
height: 100%;
width: 20%;
min-width: 20%;
background-color: slategray;
color: ghostwhite;
} .main-menu a {
color: ghostwhite;
text-align: center;
padding: 1em;
font-size: 1.5em;
} .about-menu {
width: 100%;
margin:;
padding:;
list-style-type: none;
display: flex;
background-color: slategray;
} .about-menu > li {
flex-grow:;
} .about-menu > li > a {
display: block;
width: calc(100% - 1em);
text-align: center;
text-decoration: none;
color: ghostwhite;
padding: 0.5em;
}

  pages.css

html, body, #root {
height: 100%;
}
h1 {
font-size: 3em;
color: slategray;
}
/* home 组件 */
.home {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
.home > nav {
display: flex;
justify-content: space-around;
padding: 1em;
width: calc(100% - 2em);
border-top: dashed 0.5em ghostwhite;
border-bottom: dashed 0.5em ghostwhite;
background-color: slategray;
} .home > nav a {
font-size: 2em;
color: ghostwhite;
flex-basis: 200px;
} /* 其它组件 */
section.events,
section.products,
section.contact {
flex-grow:;
margin: 1em;
display: flex;
justify-content: center;
align-items: center;
}
/* 404页面 */
.whoops-404 {
position: fixed;
top:;
left:;
z-index:;
display: flex;
width: 100%;
height: 100%;
margin:;
justify-content: center;
align-items: center;
background-color: darkred;
color: ghostwhite;
font-size: 1.5em;
} .page {
display: flex;
justify-content: space-between;
height: 100%;
padding-top: 20px;
background: #f3f7ff;
}
/* about 组件 */
.about {
flex-grow:;
margin: 1em;
display: flex;
flex-direction: column;
}
.about > section {
text-align: center;
}

React Router 4.0 ---- 嵌套路由和动态路由的更多相关文章

  1. react router 4.0以上的路由应用

    thead>tr>th{padding:8px;line-height:1.4285714;border-top:1px solid #ddd}.table>thead>tr& ...

  2. React Router 4.0 实现路由守卫

    在使用 Vue 或者 Angular 的时候,框架提供了路由守卫功能,用来在进入某个路有前进行一些校验工作,如果校验失败,就跳转到 404 或者登陆页面,比如 Vue 中的 beforeEnter 函 ...

  3. React Router 4.0 体验

    React Router 4.0 (以下简称 RR4) 已经正式发布,它遵循React的设计理念,即万物皆组件.所以 RR4 只是一堆 提供了导航功能的组件(还有若干对象和方法),具有声明式(声明式编 ...

  4. React Router 4.0 + webpack 实现组件按需加载

    网上关于React Router 4.0的按需加载文章有很多,大致的思路都一样,但是其实具体实现起来却要根据自己的实际情况来定,这里主要介绍一下我的实现方式. 主要方式是通过Route组件的rende ...

  5. 初步学习React Router 4.0

      React Router 4.0 是react官方推荐的路由库.4是已经正式发布的最新版本. 初始化项目启动之后: npm run eject 弹出配置文件.自定义配置webpack 查看下pac ...

  6. Reactjs之静态路由、动态路由以及Get传值以及获取

    1.新增知识点 /* react路由的配置: 1.找到官方文档 https://reacttraining.com/react-router/web/example/basic 2.安装 cnpm i ...

  7. CCNA - Part12 - 路由协议 (1) - 静态路由,动态路由 RIP

    路由器 在之前关于路由器的介绍中,我们知道它是网络互联的核心设备,用于连接不同的网络,在网络之间转发 IP 数据报.对于路由器来说,路由表是其内部最为重要的构成组件.当路由器需要转发数据时,就会按照路 ...

  8. vue根据后端菜单自动生成路由(动态路由)

    vue根据后端菜单自动生成路由(动态路由) router.js import Vue from 'vue' import Router from 'vue-router' import store f ...

  9. nodejs之express路由与动态路由

    1.快速创建express项目步骤 /** * 1.cd 到项目里面 * 2.npm init --yes 创建package.json文件 * 3.安装express * npm install e ...

随机推荐

  1. 洛谷 P1451 求细胞数量

    题目链接 https://www.luogu.org/problemnew/show/P1451 题目描述 一矩形阵列由数字0到9组成,数字1到9代表细胞,细胞的定义为沿细胞数字上下左右若还是细胞数字 ...

  2. Linux并发与同步专题 (1)原子操作和内存屏障

    关键词:. <Linux并发与同步专题 (1)原子操作和内存屏障> <Linux并发与同步专题 (2)spinlock> <Linux并发与同步专题 (3) 信号量> ...

  3. Linux 下配置zookeeper集群

    我们首先准备三台服务器,IP地址分别如下(前提是要先安装JDK) 192.168.100.101 192.168.100.102 192.168.100.103 1.配置主机名到IP地址的映射(此步骤 ...

  4. 1、FreeRTOS移植

    1.FreeRTOS目录结构 FreeRTOS FreeRTOS简略目录如下: ├─FreeRTOS │ ├─Demo // 各种开发工具的完整Demo,开发者可以方便的以此搭建出自己的项目,甚至直接 ...

  5. c# 设置IE浏览器版本运行程序-设置webBrowser对应的IE内核版本来运行

    //通常情况下,我们直接调用C#的webBrowser控件,默认的浏览器内核是IE7.  那么如何修改控件调用的默认浏览器版本呢?using System; using System.Collecti ...

  6. R实战 第十二篇:随机数

    由R生成的随机数实际上伪随机数,也就是说,随机数是由某种算法而不是真正的随机过程产生的,随机数生成器需要一个初始值来生成数字,该初始值叫做种子.通过把种子设置为特定的值,可以保证每次运行同一段代码时都 ...

  7. Jenkins- job之间传参

    前言: 本文介绍插件: Parameterized Trigger plugin的具体使用方法. 一.插件介绍 Parameterized Trigger plugin插件可以让你在构建完成时触发新的 ...

  8. VMware(威睿)后端开发笔试题总结

    1.   Linux中查看系统的发行版本信息 的命令? cat/etc/issue    和    lsb_release 2.   linux 挂载一个共享文件夹: mount  -t  cifc ...

  9. Randomized Online PCA Algorithms with Regret Bounds that are Logarithmic in the Dimension

    目录 Setup of Batch PCA and Online PCA Hedge Algorithm 改进算法 用于矩阵 \(rounding()\) 前俩次,都用到了\(rounding()\) ...

  10. 详解ES5和ES6的继承

    ES5继承 构造函数.原型和实例的关系:每一个构造函数都有一个原型对象,每一个原型对象都有一个指向构造函数的指针,而每一个实例都包含一个指向原型对象的内部指针, 原型链实现继承 基本思想:利用原型让一 ...