实战首页:首页组件的拆分与专题区域布局

262 阅读2分钟

1. 实现“简书”首页

我们首先分析“简书”首页的布局,可以发现整体分为左右两个部分。

image.png

左边是一个带有轮播图的专题推荐栏目,右边是一个推荐作者列表。因此,我们可以搭建一个基本的框架:

class Home extends Component{
    render(){
        return (
            <HomeWrapper>
                <HomeLeft>
                    <img className='banner-img' src='https://upload-images.jianshu.io/upload_images/13448242-20871e9f865fb242.jpg?imageMogr2/auto-orient/strip|imageView2/2/w/594/format/webp'/>
                </HomeLeft> 
                <HomeRight>Right</HomeRight>
            </HomeWrapper>
        );
    }
}

export default Home;

为了更好地组织代码,我们可以使用styled-components来渲染组件:

import styled from 'styled-components';

export const HomeWrapper = styled.div`
    overflow:hidden;
    width: 960px;
    margin: 0 auto;
`;

export const HomeLeft = styled.div`
    float:left;
    margin-left:15px;
    padding-top:30px; 
    width: 625px;
    .banner-img{
      width:625px;
      height:270px;
    }
`;

export const HomeRight = styled.div`
    width: 240px;
    float:right;
`;

2. 实现专题区域界面

首先我们希望实现类似简书首页的专题区域:

image.png

主要是实现其中 Item 的设计。我们目前的代码如下:

javascriptCopy code
import React, { Component } from 'react';
import { TopicItem, TopicWrapper } from "../style";
import { connect } from 'react-redux';

class Topic extends Component {
  render() {
    return (
      <TopicWrapper>
        <TopicItem>
          <img className='topic-pic'
               src='https://upload-images.jianshu.io/upload_images/1741702-7d340c9913d5ada8.jpg?imageMogr2/auto-orient/strip|imageView2/2/w/424/format/webp'/>
          社会热点
        </TopicItem>
        // ...
      </TopicWrapper>
    );
  }
}

export default connect()(Topic);

以下是关于样式的说明:

  • TopicWrapperoverflow 属性是为了适配 Itemfloat 样式,保证可以自己测量得到所需的高度。
  • 具体的颜色样式直接参考简书调试获取。
  • 下面的是图片的 class,display 设置为 block 是为了不影响文字的效果。
  • 其他的 margin 可能最后还需要进行微调。

3. Home 界面的数据设计

之前的 header 界面已经搭建好了基于 Redux 的数据管理框架,Home 界面也需要。这里主要是专题区域的 list 需要这个数据。

3.1 Home 的 store 目录

import { fromJS } from 'immutable';

const defaultState = fromJS({
   topicList: [{
       id:1,
       title:'社会热点',
       imgUrl:'https://upload-images.jianshu.io/upload_images/1741702-7d340c9913d5ada8.jpg?imageMogr2/auto-orient/strip|imageView2/2/w/424/format/webp'
   },{
       id:2,
       title:'手绘',
       imgUrl:'https://upload-images.jianshu.io/upload_images/1741702-7d340c9913d5ada8.jpg?imageMogr2/auto-orient/strip|imageView2/2/w/424/format/webp'
   }]
});

export default (state = defaultState, action) => {
    return state;
}

接下来,我们需要将其分配到根目录下的 reducer 中:

import { combineReducers } from 'redux-immutable';
import { reducer as headReducer } from '../common/header/store';
import { reducer as homeReducer } from '../pages/home/store';

export default combineReducers({
    header: headReducer,
    home: homeReducer
});

最后,我们需要在 Topic 组件中获取这个 list,然后循环渲染出 Item。注意,这个数据是 immutable,所以需要使用 get 方法获取数据:

import React, {Component} from 'react';
import {TopicItem, TopicWrapper} from "../style";
import {connect} from 'react-redux';


class Topic extends Component {
  render() {
    return (
      <TopicWrapper>
        {
          this.props.list.map((item) => {
            return (
              <TopicItem key={item.get('id')}>
                <img className='topic-pic'
                     src={item.get('imgUrl')}/>
                {item.get('title')}
              </TopicItem>
            )
          })
        }

      </TopicWrapper>
    );
  }
}

const mapStateToProps = (state) => ({

  list: state.get('home').get('topicList')
});

export default connect(mapStateToProps, null)(Topic);