使用React实现简书导航栏

1,166 阅读3分钟
原文链接: bingyishow.top

这次拿简书来实战。文章中用到了styled-components、react-transition-group。

实现效果

2


目录结构

目录结构如下。主要在src目录下。

1

aawwee存放下载iconfont图标压缩包。和项目无关。

statics是存放的静态文件。


安装

项目使用了styled-components、react-transition-group需要单独安装。指令分别如下:

npm install --save styled-components
//or
yarn add styled-components

npm install react-transition-group --save
//or
yarn add react-transition-group

代码

header/index.js

import React , {Component} from 'react';
import {HeaderWrapper , Logo , Nav,NavItem,NavSeach , Addition , Button,SeearchWrapper} from "./style";
import { CSSTransition } from 'react-transition-group';

class Header extends Component{

    constructor(props) {
        super(props);
        this.state = {
            focused: false
        };

        this.handleInputFocus = this.handleInputFocus.bind(this);
        this.handleInputBlur = this.handleInputBlur.bind(this);
    }


    render() {
        return(
            <HeaderWrapper>
                <Logo />
                <Nav>
                    <NavItem className={'left active'}>首页</NavItem>
                    <NavItem className={'left'}>下载App</NavItem>
                    <NavItem className={'right'}>登陆</NavItem>
                    <NavItem className={'right'}>
                        <span className="iconfont"></span>
                    </NavItem>
                    <SeearchWrapper>
                        <CSSTransition
                            in={this.state.focused}
                            timeout={200}
                            classNames="slide"
                        >
                            <NavSeach
                                className={this.state.focused ? 'focused': ''}
                                onFocus={this.handleInputFocus}
                                onBlur={this.handleInputBlur}
                            ></NavSeach>
                        </CSSTransition>
                            <span className={this.state.focused ? 'focused iconfont': 'iconfont'}>
                            
                            </span>


                    </SeearchWrapper>
                </Nav>
                <Addition>
                    <Button className={'writting'}>
                        <span className="iconfont"></span>
                        写文章
                    </Button>
                    <Button className={'reg'}>注册</Button>
                </Addition>
            </HeaderWrapper>
            )
    }

    handleInputFocus(){
        this.setState({
            focused: true
        })
    }

    handleInputBlur(){
        this.setState({
            focused: false
        })
    }

}

export default Header;

header/style.js

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.attrs({
    href: '/'
})`
    height: 56px;
    position: absolute;
    top: 0;
    left: 0;
    display: block;
    width: 100px;
    background : url(${logoPic});
    background-size: contain;
`;

export const Nav = styled.div`
    width: 960px;
    height: 100%;
    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 NavSeach = styled.input.attrs({
    placeholder: '搜索'
})`
    width: 160px;
    height: 38px;
    border: none;
    margin-top: 9px;
    margin-left: 20px;
    padding: 0 30px 0 20px;
    box-sizing: border-box;
    border-radius: 19px;
    background: #eee;
    font-size: 14px;
    color: #777;
    &::placeholder {
        color: #999;
    }
    &.focused {
        width: 240px;
        outline: none;
    }
    
`;

export const Addition = styled.div`
    position: absolute;
    right: 0;
    top: 0;
    height: 56px;
`;

export const Button = styled.div`
    float: right;
    font-size: 14px;
    margin-top: 9px;
    margin-right: 20px;
    padding: 0 20px;
    line-height: 38px;
    border-radius: 19px;
    border: 1px solid #ec6149;
    &.reg{
        color: #ec6149;
    }
    &.writting{
        color: #fff;
        background: #ec6149;
    }
`;

export const SeearchWrapper = styled.div`
    float:left;
    position: relative;
    .iconfont {
        position: absolute;
        right: 5px;
        bottom: 5px;
        width: 30px;
        line-height: 30px;
        text-align: center;
        border-radius: 15px;
        &.focused{
            background: #777;
            color: #fff;
        }
    }
    .slide-enter{
            transition: all .2s ease-out;
    }
    .slide-enter-active {
            width: 240px;
    }
    .slide-exit {
        transition: all .2s ease-out;
    }
    .slide-exit-active {
        width: 160px;
    }
`;

App.js

import React, { Component } from 'react';
import {InjectGlobal} from "./style";
import Header from './common/header'
import {IconInjectGlobal} from "./statics/iconfont/iconfont";


class App extends Component {
  render() {
    return (
      <div>
        <InjectGlobal/>
        <IconInjectGlobal/>
        <Header/>
      </div>
    );
  }
}

export default App;

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));

style.js

import {createGlobalStyle} from 'styled-components';

export const InjectGlobal = createGlobalStyle`
  html, body, div, span, applet, object, iframe,
  h1, h2, h3, h4, h5, h6, p, blockquote, pre,
  a, abbr, acronym, address, big, cite, code,
  del, dfn, em, img, ins, kbd, q, s, samp,
  small, strike, strong, sub, sup, tt, var,
  b, u, i, center,
  dl, dt, dd, ol, ul, li,
  fieldset, form, label, legend,
  table, caption, tbody, tfoot, thead, tr, th, td,
  article, aside, canvas, details, embed, 
  figure, figcaption, footer, header, hgroup, 
  menu, nav, output, ruby, section, summary,
  time, mark, audio, video {
      margin: 0;
      padding: 0;
      border: 0;
      font-size: 100%;
      font: inherit;
      vertical-align: baseline;
  }
  /* HTML5 display-role reset for older browsers */
  article, aside, details, figcaption, figure, 
  footer, header, hgroup, menu, nav, section {
      display: block;
  }
  body {
      line-height: 1;
  }
  ol, ul {
      list-style: none;
  }
  blockquote, q {
      quotes: none;
  }
  blockquote:before, blockquote:after,
  q:before, q:after {
      content: '';
      content: none;
  }
  table {
      border-collapse: collapse;
      border-spacing: 0;
  }
`;

打包下载

整个src文件夹打包如下。

asytech.cn/cloud/index…