本文主要實現ListView的適配器功能,基本可以解決列表的絕大部分問題,原文可查看React 自定義ListView組件-適配模式
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可以在任意頁面調用使用,只需在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組件或者方法返回均可。