本文主要实现ListView的适配器功能,基本可以解决列表的绝大部分问题,原文可查看React 自定义ListView组件-适配模式
通过适配器的实现,适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。这样就可以让ListView如同Android中的ListView一样动态设置Item布局、数据格式,Item类型等。
/* eslint no-dupe-keys: 0 */
import React, { Component } from "react";
class ListView extends Component{
constructor(props) {
super(props);
// console.log("get props:",this.props)
this.state = {
data: props.data?props.data:[],
};
}
componentDidMount() {
//组件首次加载时
console.log("get componentDidMount props:",this.props)
};
componentWillReceiveProps(nextProps){
if(this.props.data != nextProps.data){
this.setState({
data:nextProps.data?nextProps.data:[],
})
}
};
/**
*
* @param {*子布局数据格式} item
* @param {*子布局位置} index
*/
getItem(item,index){
let itemLayout = this.props.adapter(item,index,{onClick:this.onItemClick.bind(this,item,index)})
return itemLayout
};
onItemClick(item,index){
console.log("-------------pre click log--------------")
return this.props.OnItemClick(item,index)
};
render() {
return (
<div className="list" >
{
{
!!this.state.data?(this.state.data.map((item,index) => {
return this.getItem(item,index)
})):null
}
}
</div>
);
}
}
export default ListView;
ListView可以在任意页面调用使用,只需在listView中指定adapter适配内容和点击操作接口即可,代码调用如下:
import React, { Component } from "react";
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import {
NavBar,
Icon,
Carousel,
WingBlank,
NoticeBar,
WhiteSpace,
} from "antd-mobile";
import { StickyContainer, Sticky } from "react-sticky";
import ListView from "./listview";
import * as homeActions from "../redux/reduces/home";
import { Toast } from "../../node_modules/antd-mobile/lib/index";
import axios from "axios";
axios.defaults.timeout = 100000;
axios.defaults.baseURL = "http://test.mediastack.cn/";
/**
* http request 拦截器
*/
axios.interceptors.request.use(
(config) => {
config.data = JSON.stringify(config.data);
config.headers = {
"Content-Type": "application/json",
};
return config;
},
(error) => {
return Promise.reject(error);
}
);
@connect(
(state) => ({ home: state.home }),
(dispatch) => bindActionCreators(homeActions, dispatch)
)
class Home extends Component {
state = {
data: ["1", "2", "3"],
imgHeight: 176,
};
constructor(props) {
super(props);
setTimeout(() => {
this.setState({
data: [
"AiyWuByWklrrUDlFignR",
"TekJlZRVCjLFexlOCuWn",
"IJOtIlfsYdTyaDTRVrLI",
],
});
}, 100);
}
componentDidMount() {
axios.get('/article/home/index').then(
(res) => {
this.setState({
list: res.data.data,
});
console.log("get article response:", res);
},
(error) => {
console.log("get response failed:", error);
}
);
}
handleBrowserChange = () => {
const { history, changeRoute } = this.props;
changeRoute();
history.push("/docs");
};
/**
* 推荐内容适配器
* @param {*} item
* @param {*} index
*/
RecommentAdapter(item, index,props) {
return (
<div
{...props}
className="item"
style={{
height: 80,
backgroundColor: "#fff",
textAlign: "left",
padding: "0 15px 0",
display: "flex",
fontSize: 20,
flexFlow: "column nowrap",
justifyContent: "center",
marginBottom: 10,
}}
key={index}
>
<label
className="title"
style={{
minWidth: 0,
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
}}
>
{item.title}
</label>
<div style={{
fontSize:12,
marginTop:12,
color:'#888888'
}}>
<span style={{
color:'#111111',
fontWeight:'500',
}}>{item.category}</span> |
<span> {item.author}</span> |
<span> 阅读量:{item.views}</span> |
<span> {item.date}</span>
</div>
</div>
);
};
onItemClick(item,index){
Toast.show("你点击的第"+index+"个item.",Toast.SHORT)
};
render() {
return (
<div className="home">
<StickyContainer>
<Sticky>
{({
style,
isSticky,
wasSticky,
distanceFromTop,
distanceFromBottom,
calculatedHeight,
}) => (
<NavBar
style={{
...style,
zIndex: 3,
padding: "2px 0",
}}
mode="light"
icon={<Icon type="left" />}
onLeftClick={() => console.log("onLeftClick")}
rightContent={[
<Icon
key="0"
type="search"
style={{ marginRight: "16px" }}
/>,
<Icon key="1" type="ellipsis" />,
]}
>
胖蔡杂谈
</NavBar>
)}
</Sticky>
{/* Sticky 为悬浮框 */}
<WingBlank>
<WhiteSpace size="lg" />
<Carousel
autoplay={false}
infinite
beforeChange={(from, to) =>
console.log(`slide from ${from} to ${to}`)
}
afterChange={(index) => console.log("slide to", index)}
>
{this.state.data.map((val) => (
<a
key={val}
href="http://www.alipay.com"
style={{
display: "inline-block",
width: "100%",
height: this.state.imgHeight,
}}
>
<img
src={`https://zos.alipayobjects.com/rmsportal/${val}.png`}
alt=""
style={{
width: "100%",
verticalAlign: "top",
}}
onLoad={() => {
// fire window resize event to change height
window.dispatchEvent(new Event("resize"));
this.setState({
imgHeight: "auto",
});
}}
/>
</a>
))}
</Carousel>
<WhiteSpace size="lg" />
<NoticeBar
marqueeProps={{ loop: true, style: { padding: "0 7.5px" } }}
>
通知:北京继续暂停出租车顺风车出京运营
合肥明日继续新一波消费券发放,预计发放4000万元
</NoticeBar>
<WhiteSpace size="lg" />
<ListView data={this.state.list}
adapter={this.RecommentAdapter}
OnItemClick={this.onItemClick}/>
</WingBlank>
</StickyContainer>
</div>
);
}
}
export default Home;
adapter 返回单个Item的jsx,可通过React组件或者方法返回均可。