为了让大家理解布局和路由的原理,本章节所实现的代码功能并不是完备的,因此本章节源码和主教程代码库是分开的。感兴趣的同学可以通过以下链接下载本章节源码进行参考:
什么是布局?
想象一下你最近搬家搬到一个新的房间,房间不大,但你有非常多的行李要放置进去。为了不让这个房间变得凌乱和难以找到自己想要的东西,你决定好好规划这个空间。从哪里开始呢?从大件到小件,床最好对着阳台,书桌可以贴近窗户,这样视野较好,柜子放在过道,架子划分成多个格子,分别放书籍、杯子、日用品……
发现没?你正在为你的房间进行布局,把东西放在合适的地方,使其便于找寻也赏心悦目。实际上,网页布局也是类似的道理。网页本质上是信息展现传达的媒介,一般交互设计阶段,首先要确定的就是网页的布局,因为要传达给用户的信息量很多,随意塞到页面上会使得信息的获取成本很高,因此如同布置房间一样,需要把合适的信息放到合适的地方。网页布局是信息组织的骨架,好的网页布局,能让信息组织清晰明了,网页更高效的完成信息传达,使用者花费很少的成本就能获取到所需的信息,且在整个网站生长运营中维持信息结构的稳定性。如下图就是常见的一些网页布局方式:
Props.children 和容器类组件
本节参考React.js 小书props.children 和容器类组件 部分
要知道怎么用React实现布局首先要了解容器类组件和 {props.children}
的用法。有一类组件,充当了容器的作用,它定义了外层的结构形式,然后可以往里面放任意的内容,这是一种很常见的结构,比如一个Card组件,组件本身是个不带任何内容的方形容器,我们可以在用这个组件的时候给它传入任意内容:
我们很容易可以实现这种容器组件:
class Card extends Component {
render () {
return (
<div className='card'>
<div className='card-content'>
{this.props.content}
</div>
</div>
)
}
}
// 比如渲染包含 “Ant Design 实战教程” 字样的div
ReactDOM.render(
<Card content={
<div>
Ant Design 实战教程
</div>
} />,
document.getElementById('root')
)
我们通过给 Card
组件传入 content
属性,这个属性可以传入任意的 jsx 结构,然后在 Card
内部会通过 {this.props.content}
把内容渲染到页面上。但这样用并不优雅,如果 Card
还有其他属性的话,这些 jsx 就会和其他属性混起来,很不好维护。如果组件标签也能像普通的 HTML 标签那样编写内嵌的结构,那么就方便很多了。比如:
ReactDOM.render(
<Card>
<div>
Ant Design 实战教程
</div>
</Card>,
document.getElementById('root')
)
实际上 React.js 默认就支持这种写法,所有嵌套在组件中的 jsx 结构都可以在组件内部通过 props.children
获取到
class Card extends Component {
render () {
return (
<div className='card'>
<div className='card-content'>
{this.props.children}
</div>
</div>
)
}
}
React.js 就是把我们嵌套的 jsx 元素一个个都放到数组当中,然后通过 {props.children} 传给了 Card
,然后 jsx 会把数组中的 jsx 一个个进行展示。
这种嵌套的内容成为了 props.children
数组的机制使得我们编写组件变得非常的灵活,我们甚至可以在组件内部把数组中的 jsx 元素安置在不同的地方:
class Layout extends Component {
render () {
return (
<div className='two-cols-layout'>
<div className='sidebar'>
{this.props.children[0]}
</div>
<div className='main'>
{this.props.children[1]}
</div>
</div>
)
}
}
这是一个两列布局组件,嵌套的 JSX 的第一个结构会成为侧边栏,第二个结构会成为内容栏,其余的结构都会被忽略。这样通过这个布局组件,就可以在各个地方高度复用我们的布局。
使用Ant Design实现基本布局
了解了容器组件和 props.children
, 那么我们来看如何用Ant Design实现一套标准布局。 Ant Design 提供了多种布局方式,比如下图就是一种典型布局方式,这个布局可以分为三个信息块: 顶部导航 Header
、侧边栏 Sider
、内容区 Content
。
下面我们在上一节的工程基础上分步骤实现上述布局。
第一步:添加基本布局
在 src
目录下创建 layout
文件目录,然后创建 index.js
文件,在 index.js
中我们写入:
import { Component } from 'react';
import { Layout } from 'antd';
// Header, Footer, Sider, Content组件在Layout组件模块下
const { Header, Footer, Sider, Content } = Layout;
class BasicLayout extends Component {
render() {
return (
<Layout>
<Sider>Sider</Sider>
<Layout>
<Header>Header</Header>
<Content>Content</Content>
<Footer>Footer</Footer>
</Layout>
</Layout>
)
}
}
export default BasicLayout;
上面代码中,我们创建了一个三部分的基本布局:Header
、Content
、Footer
。然后我们将 Content
替换成 { this.props.children }
,这样之后我们设置的路由会通过替换 children 变量实现内容的切换。
<Content>{ this.props.children }</Content>
第二步:添加样式
上面我们定义了导航的结构,下面我们添加一些样式,让这个布局看上去更美观一些:
import { Component } from 'react';
import { Layout } from 'antd';
const { Header, Footer, Sider, Content } = Layout;
export default class BasicLayout extends Component {
render() {
return (
<Layout>
<Sider width={256} style={{ minHeight: '100vh', color: 'white' }}>
Sider
</Sider>
<Layout >
<Header style={{ background: '#fff', textAlign: 'center', padding: 0 }}>Header</Header>
<Content style={{ margin: '24px 16px 0' }}>
<div style={{ padding: 24, background: '#fff', minHeight: 360 }}>
{this.props.children}
</div>
</Content>
<Footer style={{ textAlign: 'center' }}>Ant Design ©2018 Created by Ant UED</Footer>
</Layout>
</Layout>
)
}
}
第三步:配置路由
定义好容器组件之后,我们就可以通过路由配置的方式把路由对应的组件渲染到容器组件中去了,具体路由如何配置我们放在下面的章节中讲述。这里我们直接在 config.js
添加路由配置:
routes: [{
path: '/',
component: '../layout',
routes: [
{
path: 'helloworld',
component: './HelloWorld'
},
]
}],
这样访问 localhost:xxxx
(注意替换成你命令行中的端口)的展示效果如下:
结语
恭喜,至此我们就实现了一个基本网页的布局了。
目前我们的侧边栏空无一物,下一章我们来设计实现一个典型的侧边栏。