呃,我们的搜索框,为了不让输入的字符串把放大镜遮住,我们给input 设置padding-right 为30px,如下。
export const NavSearch = styled.input`
width: 160px;
height: 38px;
margin-top: 9px;
margin-left: 20px;
padding: 0 30px 0 20px;
box-sizing: border-box;
border: none;
outline: none;
border-radius: 19px;
background: #eee;
font-size: 14px;
color: #777;
&::placeholder {
color: #999;
}
`;
接下来,我们制作鼠标的移入移出动画效果。
我们可以通过数据,控制页面的变化。在Header 组件中,我们在组件的state 中定义一个变量 focused ,如下。
constructor(props) {
super(props);
this.state = {
focused: false
}
}
然后,我们控制一下 NavSearch 与放大镜 的 className,如下。
return (
<HeaderWrapper>
<Logo href='/'/>
<Nav>
<NavItem className='left active'>首页</NavItem>
<NavItem className='left'>下载</NavItem>
<NavItem className='right'>登录</NavItem>
<NavItem className='right'>
<span className="iconfont"></span>
</NavItem>
<SearchWrapper>
<NavSearch
placeholder="搜索"
className={this.state.focused ? "focused" : ""}
></NavSearch>
<span
className={this.state.focused ? "focused iconfont" : "iconfont"}
></span>
</SearchWrapper>
</Nav>
<Addition>
<Button className='writting'>
<span className="iconfont"></span>
写文章
</Button>
<Button className='reg'>注册</Button>
</Addition>
</HeaderWrapper>
)
然后,我们去增加一些样式,如下。
export const SearchWrapper = styled.div`
position: relative;
float: left;
background:red;
.iconfont {
position: absolute;
right: 5px;
bottom: 5px;
width: 30px;
line-height: 30px;
border-radius: 15px;
text-align: center;
&.focused {
background: #777;
color: #fff;
}
}
`;
export const NavSearch = styled.input`
width: 160px;
height: 38px;
margin-top: 9px;
margin-left: 20px;
padding: 0 30px 0 20px;
box-sizing: border-box;
border: none;
outline: none;
border-radius: 19px;
background: #eee;
font-size: 14px;
color: #777;
&::placeholder {
color: #999;
}
&.focused {
width: 200px;
}
`;
然后,我们增加一些逻辑处理,给输入框 的 focus 和 blur 事件定义逻辑,如下。
<NavSearch
placeholder="搜索"
className={this.state.focused ? "focused" : ""}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
></NavSearch>
handleFocus() {
this.setState({
focused: true
})
}
handleBlur() {
this.setState({
focused: false
})
}
下面,我们使用一下动画,使得样式变化可以平滑一些。动画,我们使用react 的第三方模块 react-transition-group 。
github 上我们可以找到它的文档: https://reactcommunity.org/react-transition-group/
然后我们使用这个模块的CSSTransition 模块就行。
下面,我们就使用吧。先下载安装它 yarn add react-transition-group
然后我们在Header 组件中引入
import { CSSTransition } from 'react-transition-group';
然后,我们用 CSSTransition标签 将 NavSearch标签包裹起来。并在 CSSTransition 中设置一些属性 timeout(动画在多少毫秒内完成),in(控制入场和出场),classNames。如下。
<SearchWrapper>
<CSSTransition
in={this.state.focused}
timeout={200}
classNames="slide"
>
<NavSearch
placeholder="搜索"
className={this.state.focused ? "focused" : ""}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
></NavSearch>
</CSSTransition>
<span
className={this.state.focused ? "focused iconfont" : "iconfont"}
></span>
</SearchWrapper>
好啦,这样的话。接下来,CSSTransition 会做下面的事情。当 in 中内容变为 true 时,它会在CSSTransition 包裹的组件上 挂载 slide-enter , slide-enter-active 样式,在in 中内容变为 false时,它会在CSSTransition 组件上 挂载 slide-exit , slide-exit-active 样式。
好啦,下面我们来写一下样式文件。
export const SearchWrapper = styled.div`
position: relative;
float: left;
.slide-enter {
transition: all .2s ease-out;
}
.slide-enter-active {
width: 240px;
}
.slide-exit {
transition: all .2s ease-out;
}
.slide-exit-active {
width: 160px;
}
.iconfont {
position: absolute;
right: 5px;
bottom: 5px;
width: 30px;
line-height: 30px;
border-radius: 15px;
text-align: center;
&.focused {
background: #777;
color: #fff;
}
}
`;
好啦,这样就实现了搜索框的动画效果。
下面,贴一下整体代码。
Header组件代码
import React, { Component } from 'react';
import {
HeaderWrapper,
Logo,
Nav,
NavItem,
NavSearch,
Addition,
Button,
SearchWrapper
} from './style';
import '../../statics/iconfont/iconfont.css';
import { CSSTransition } from 'react-transition-group';
class Header extends Component {
constructor(props) {
super(props);
this.state = {
focused: false
}
this.handleFocus = this.handleFocus.bind(this);
this.handleBlur = this.handleBlur.bind(this);
}
render () {
return (
<HeaderWrapper>
<Logo href='/'/>
<Nav>
<NavItem className='left active'>首页</NavItem>
<NavItem className='left'>下载</NavItem>
<NavItem className='right'>登录</NavItem>
<NavItem className='right'>
<span className="iconfont"></span>
</NavItem>
<SearchWrapper>
<CSSTransition
in={this.state.focused}
timeout={200}
classNames="slide"
>
<NavSearch
placeholder="搜索"
className={this.state.focused ? "focused" : ""}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
></NavSearch>
</CSSTransition>
<span
className={this.state.focused ? "focused iconfont" : "iconfont"}
></span>
</SearchWrapper>
</Nav>
<Addition>
<Button className='writting'>
<span className="iconfont"></span>
写文章
</Button>
<Button className='reg'>注册</Button>
</Addition>
</HeaderWrapper>
)
}
handleFocus() {
this.setState({
focused: true
})
}
handleBlur() {
this.setState({
focused: false
})
}
}
export default Header;
Header组件的样式代码
import styled from 'styled-components';
import logoPic from '../../statics/logo.png';
export const HeaderWrapper = styled.div`
position: relative;
height: 56px;
border-bottom: 1px solid #f0f0f0;
`;
export const Logo = styled.a`
position: absolute;
top: 0;
left: 0;
display: block;
width: 100px;
height: 56px;
background: url(${logoPic});
background-size: contain;
`;
export const Nav = styled.div`
width: 960px;
height: 100%;
padding-right: 70px;
box-sizing: border-box;
margin: 0 auto;
`;
export const NavItem = styled.div`
line-height: 56px;
padding: 0 15px;
font-size: 17px;
color: #333;
&.left {
float: left;
}
&.right {
float: right;
color: #969696;
}
&.active {
color: #ea6f5a;
}
`;
export const SearchWrapper = styled.div`
position: relative;
float: left;
.slide-enter {
transition: all .2s ease-out;
}
.slide-enter-active {
width: 240px;
}
.slide-exit {
transition: all .2s ease-out;
}
.slide-exit-active {
width: 160px;
}
.iconfont {
position: absolute;
right: 5px;
bottom: 5px;
width: 30px;
line-height: 30px;
border-radius: 15px;
text-align: center;
&.focused {
background: #777;
color: #fff;
}
}
`;
export const NavSearch = styled.input`
width: 160px;
height: 38px;
margin-top: 9px;
margin-left: 20px;
padding: 0 30px 0 20px;
box-sizing: border-box;
border: none;
outline: none;
border-radius: 19px;
background: #eee;
font-size: 14px;
color: #777;
&::placeholder {
color: #999;
}
&.focused {
width: 200px;
}
`;
export const Addition = styled.div`
position: absolute;
top: 0;
right: 0;
height: 56px;
`;
export const Button = styled.div`
float: right;
margin-top: 9px;
margin-right: 20px;
padding: 0 20px;
line-height: 38px;
border-radius: 19px;
border: 1px solid #ec6149;
font-size: 14px;
&.reg {
color: #ec6149;
}
&.writting {
color: #fff;
background: #ec6149;
}
`;
Done.