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

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

  这个共有内容要怎么处理? 首先想到的就是把这个功能提取出来,写成一个组件,然后再把这个组件依次应用到其它路由组件,如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. BZOJ1390 CEOI2008 Fences 凸包、Floyd最小环/DP

    传送门 为了方便描述把固定点叫做白色点,Tree叫做黑色点 一种基于特殊性质的做法: 如果不算入选白色的权值,那么一定会选中所有白色点构成的凸包上的点,因为能够尽可能围更多的黑色点.然后我们在这个基础 ...

  2. mysql基本知识点梳理和查询优化

    目录 一.索引相关 二.EXPLIAN中有用的信息 三.字段类型和编码 四.SQL语句总结 五.踩坑 六.千万大表在线修改 七.慢查询日志 八.查看sql进程和杀死进程 九.一些数据库性能的思考 本文 ...

  3. node express 静态资源

    实例代码 const express = require('express') const path = require('path') const app = express() app.use(e ...

  4. 教你使用HTML5原生对话框元素,轻松创建模态框组件

    HTML 5.2草案加入了新的dialog元素.但是是一种实验技术. 以前,如果我们想要构建任何形式的模式对话框或对话框,我们需要有一个背景,一个关闭按钮,将事件绑定在对话框中的方式安排我们的标记,找 ...

  5. Eclipse新建Maven工程——git篇

    1.eclipse,新建一个maven工程,步骤如下图: 右键新建的工程 发布前后工程对比如下: 2.发布为本地仓库 因为项目中,不是所有的文件,都需要提交到githut上,所以需要把不需要提交的问题 ...

  6. Python_架构、同一台电脑上两个py文件通信、两台电脑如何通信、几十台电脑如何通信、更多电脑之间的通信、库、端口号

    1.架构 C/S架构(鼻祖) C:client  客户端 S:server  服务器 早期使用的一种架构,目前的各种app使用的就是这种架构,它的表现形式就是拥有专门的app. B/S架构(隶属于C/ ...

  7. C#复习笔记(3)--C#2:解决C#1的问题(实现迭代器的捷径)

    实现迭代器的捷径 从这个题目上可以看到C#1实现一个迭代器模式的话是多么的痛苦,我自己也写过不下40行的代码来实现一个迭代器,C#中的迭代器模式是通过IEnumerable和他的泛型等价物IEnume ...

  8. css3新属性box-orient

    前言 box-orient属性经常与display:box属性结合使用 div { width:350px; height:100px; border:1px solid black; /* Fire ...

  9. 2 Modals of necessity

    1 情况动词must 和词组have to, need to ,have got to 都表示必须做某事或者要求做某事. need to  have to  must have got to When ...

  10. linux 服务器名 访问 shh免密码登录

    以根用户登录,或者登录后切换到根用户,然后在提示符下输入hostname命令,可以看出当前系统的主机名为localhost.localdomain.   更改/etc/sysconfig下的netwo ...