导航栏
导航栏首先简单分析一下这个导航栏的组成,可以划分两部分:logo和导航链接区域。
根据这个划分,,我们可以开始写组件的DOM结构和定义样式名字:
import React from 'react';
import styles from './styles.scss';
class TopNav extends React.Component {
render() {
return (
<div className={styles.container}>
<div className={styles.logo}></div>
<div className={styles.nav}>
<nav>
<ul>
<li><button>成为房东</button></li>
<li><button>帮助</button></li>
<li><button>注册</button></li>
<li><button>登录</button></li>
</ul>
</nav>
</div>
</div>
);
}
}
export default TopNav;
刷新页面,此时,你的页面大概长成这样:
现在,我们可以开始添加样式到./TopNav/styles.scss:
.container {
font-family: Circular,-apple-system,BlinkMacSystemFont,Roboto,Helvetica Neue,sans-serif;
}
.logo {
background-image: url("./logo.svg");
background-repeat: no-repeat;
background-position: center center;
height: 34px;
width: 34px;
display: inline-block;
vertical-align: middle;
}
.nav {
display: inline-block;
float: right;
ul {
padding: 0;
}
li {
display: inline-block;
list-style: none;
button {
background: transparent;
border: none;
font-size: 14px;
color: #484848;
margin: 0 16px;
cursor: pointer;
padding: 0 0 5px 0;
-webkit-font-smoothing: antialiased;
&:hover {
border-bottom: 2px solid #484848;
}
}
}
}
这样,NavTop的基本样式和DOM结构就完成了,到目前为止,我们通过React实现了一个纯展示组件(Presentational Component),它没有任何的状态(state)和行为。(请仔细阅读《Presentational and Container Components》)
弹出框
导航栏的第二步,是给链接添加PopupMenu弹出框,并通过组件的状态来控制弹出框的toggle。
PopupMenu它是一个独立的组件,这个时候,我们可以考虑在NavTop目录下新建一个PopupMenu.jsx来构建该组件。
在开始写组件之前,我们先引入classnames来帮助管理class的状态(class的组合),因为,我们使用了CSS Modules,所以需要使用它的bind版本 ,classnames bind version for css modules。
yarn add classnames
同理,我们可以根据设计给出PopupMenu的DOM结构:
import React from 'react';
import classNames from 'classnames/bind';
import styles from './PopupMenu.scss';
const cx = classNames.bind(styles);
class PopupMenu extends React.PureComponent {
render() {
return (
<div className={cx('container', this.props.className)}>
<ul>
{
this.props.links.map(link => (<li key={`pop-mnu-li${link.id}`}><a href={link.href}><div>{link.title}</div></a></li>))
}
</ul>
</div>);
}
}
PopupMenu.propTypes = {
links: React.PropTypes.arrayOf(React.PropTypes.object)
}
export default PopupMenu;
这里使用了PureComponent而不是Component,原因是,我们知道PopupMenu组件是一个Presentational组件,到这里了解PureComponent是什么以及Component渲染性能。
然后,我们需要修改TopNav/index.jsx来控制PopupMenu的显示:
import React from 'react';
import classNames from 'classnames/bind';
import styles from './styles.scss';
import PopupMenu from './PopupMenu';
const cx = classNames.bind(styles);
class TopNav extends React.Component {
constructor(props) {
super(props);
this.state = {
showLandlordMenu: false
};
}
toggleShowLandlordMenu = (toggleOff = false) => {
this.setState({
showLandlordMenu: !toggleOff && !this.state.showLandlordMenu
});
}
render() {
return (
<div className={cx('container')}>
<div className={cx('logo')}></div>
<div className={cx('nav')}>
<nav>
<ul>
<li>
<button onClick={() =>this.toggleShowLandlordMenu()} onBlur={() => this.toggleShowLandlordMenu(true)}>成为房东</button>
<PopupMenu
className={cx('landlord-menu', { 'hidden': !this.state.showLandlordMenu })}
links={[{ id: 1, title: '出租房源', href: '' }, { id: 2, title: '展开体验', href: '' }]}
/>
</li>
<li><button>帮助</button></li>
<li><button>注册</button></li>
<li><button>登录</button></li>
</ul>
</nav>
</div>
</div>
);
}
}
export default TopNav;
onBlur的作用是当用户点击到PopupMenu之外的部分时,可以让组件消失。
这个时候,可以先不管PopupMenu的样式,直接测试弹出和消失的功能是否工作。
最后添加PopupMenu组件的样式:
.container {
background-color: #ffffff;
border: 1px solid #DBDBDB;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
min-width: 282px;
max-width: 460px;
min-height: 60px;
right: 0px;
top: 40px;
li {
display: block;
color: #484848;
a {
display: block;
text-decoration: none;
color: #767676;
font-family: Circular,-apple-system,BlinkMacSystemFont,Roboto,Helvetica Neue,sans-serif;
word-wrap: break-word;
font-size: 15px;
line-height: 18px;
letter-spacing: 0.2px;
padding: 0 16px;
div {
border-bottom: 1px solid transparent;
padding: 16px 0;
border-color: #F2F2F2;
&:hover {
border-color: #767676;
}
}
}
}
}
.container:after, .container:before {
content: '';
display: block;
position: absolute;
left: 226px;
width: 0;
height: 0;
border-style: solid;
}
.container:after {
top: -22px;
border-color: transparent transparent white transparent;
border-width: 11px;
}
.container:before {
top: -23px;
border-color: transparent transparent #DBDBDB transparent;
border-width: 11px;
}
代码
你可以在prepare-env分支查看到当前步骤所有的代码
git clone [email protected]:ThoughtWorksWuhanUI/react-zero-to-one.git
git checkout nav-top
本页编辑:Benwei