一直直在写一个前端项目,来分享一些Scroll封装的实践
设计目标
因为项目中需要大量的类似Scroll List,ListView页面:
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
- 封装后总体Scroll List比较优雅和快捷
- 但是欠缺性能优化,使用immutable、shouldComponentUpdate优化性能
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。