2
一直直在写一个前端项目,来分享一些Scroll封装的实践

设计目标

因为项目中需要大量的类似Scroll List,ListView页面:

clipboard.png

github上看了圈感觉没有特别喜欢的,就自己来封装了一下
层次结构如下:

|-Scroll//主要处理诸如下拉刷新,上拉加载,加载状态,错误信息等
|-----List //主要是List主体 
|--------ListEl //返回List里单个Component,

使用方式

可以像这样简洁的使用这个封装的Scroll List(or List View)
有种来到了开发Windows RT、WPF使用ListView template的即视感

    <Scroll
        firstLoading={foo.FirstLoading}
        fistLoading={foo.ListLoading}
        isEnd={foo.isEnd}
        isFetch={foo.isFetch}
        fetchFailed={foo.fetchFailed}
        failedMag={foo.failedMag}
    >
        <List
            entities={coursecate.entities}
            result={coursecate.result}
            type={'samllCourseCate'}
        >
        </List>
    </Scroll>

开始封装

说明:JSON格式扁平化(normalizr)

我在项目中使用normalizer来格式扁平化JSON数据

开发复杂的应用时,不可避免会有一些数据相互引用。建议你尽可能地把 state 范式化,不存在嵌套。把所有数据放到一个对象里,每个数据以 ID 为主键,不同数据相互引用时通过 ID 来查找。把 应用的 state 想像成数据库 。这种方法在 normalizr 文档里有详细阐述。
normalizr:将嵌套的JSON格式扁平化,方便被Redux利用;
举个例子

[{
  id: 1,
  title: 'Some Article',
  author: {
    id: 1,
    name: 'Dan'
  }
}, {
  id: 2,
  title: 'Other Article',
  author: {
    id: 1,
    name: 'Dan'
  }
}]

处理后会变成

{
  result: [1, 2],
  entities: {
    articles: {
      1: {
        id: 1,
        title: 'Some Article',
        author: 1
      },
      2: {
        id: 2,
        title: 'Other Article',
        author: 1
      }
    },
    users: {
      1: {
        id: 1,
        name: 'Dan'
      }
    }
  }
}

CommonScorll.js

import React, { PropTypes, Component } from 'react';

class CommonScorll extends Component {
    constructor(props) {
        super(props);
        const {FirstLoading,ListLoading} =this.props;
        this.ListScroll=this.ListScroll.bind(this);
        this.FirstLoading=()=>FirstLoading();
        this.ListLoading=()=>ListLoading();
    }
    componentDidMount() {
        console.log('common scroll componentDidMount')       
        //下拉刷新监听绑定
        window.addEventListener('scroll', this.ListScroll);
        //初次Load
        this.FirstLoading;
    }
    componentWillUnmount(){
        //移除监听
        window.removeEventListener('scroll', this.ListScroll);
    }
    ListScroll(e) {
        var scrollTop = document.body.scrollTop; 
        var offsetHeight = document.body.offsetHeight; 
        var scrollHeight = document.body.scrollHeight; 
        if (scrollTop >= scrollHeight - offsetHeight) { 
             this.ListLoading;
        } 
    }
    render(){
        console.log('common scroll render')
        const {
            isFetch,
            isEnd,
            fetchFailed,
            failedMsg,
            EmptyElement
                }=this.props;
        let NoMore=();
        if(isEnd){
            NoMore=(
                ...
            );
        }
        ...//根据你的需求处理 底部如:加载更多,加载失败时重新加载等
        
        return(
            <div >
               {this.props.children}//因为List主体是被包裹在Scroll中的,所以加载children
               ...    
            </div>
        );
    }

}

export default CommonScorll;

CommonList.js

import React, { PropTypes, Component } from 'react';
import {ListEl} from './ListEl'

class CommonList extends Component {
    constructor(props) {
        super(props);
    }
    componentDidMount() {
        console.log('common list componentDidMount')       
    }
    render(){
            console.log('common list render')
            const {
                    entities,
                    result,
                    type
                    }=this.props;
                    //数据经过normalize格式化
            let datas=[<div key=0/>];
            if(result.length!==0){
                datas=[];
                result.forEach(function(id) {
                    datas.push(ListEl(id,entities,type))//ListEl是一个function 
                })
            }
            return(
                <div>
                    {datas}
                </div>
            );
        }
}

export default CommonList;

ListEl.js

import React, { PropTypes, Component } from 'react';
import SmallCourseCate from '../Common/CourseCate/SmallCourseCate'

export function ListEl(id,entites,type) {
    switch (type) {
        case 'samllCourseCate':
            if(entites.coursecates[id]){
                let coursecate=entites.coursecates[id];
                return(
                    <SmallCourseCate
                        key={id}
                        coursecate={coursecate}
                    />
                )
            }else{
                return (
                    <div>
                    <p>small coursecate el try get coursecate is null</p>
                    </div>
                )
            }
        ...
        default:
        return (
            <div>
                <p>el type undefind</p>
            </div>
        )
    }
}

总结&TODO

  1. 封装后总体Scroll List比较优雅和快捷
  2. 但是欠缺性能优化,使用immutable、shouldComponentUpdate优化性能

Weny
47 声望4 粉丝

Wenyxu