第一篇 https://segmentfault.com/a/11...react
在上一篇文章中教給你們了怎麼搭建項目的架子;那麼今天咱們就來講一下項目裏的導航和列表的實現json
廢話不說啦 下面直接給你們講一下代碼
項目用的antd-mobile的框架 應該沒什麼難度,我相信你們認真看文檔的都能佈局出來;segmentfault
TabButton.jsapi
import React, { Component } from 'react'; import { Tabs, WhiteSpace,ListView,Toast} from 'antd-mobile'; import { routerRedux } from 'dva/router'; import { connect } from 'dva'; import Request from '../common/fetch' import {width,height} from '../common/style'; const TabPane = Tabs.TabPane; class TabButton extends Component { constructor(props) { super(props); this.state = { channels: [] } } componentDidMount() { // 這個地方是封裝的fetch請求; Request('/api/article/channel',{ secret:1111, },((res) => { this.setState({ channels: res.result.channels }) // 請求過來的數據所有存下來,以便後期調用,同時能夠減小請求 this.props.dispatch({ type: 'indexList/TabData', payload: res.result.channels, }); })) } //這個點須要注意:此處是將click事件傳遞給子組件,另外一界面 <TabButton ButtonClick ={this.ButtonClick.bind(this)} />就能夠取到此組件傳遞過去的click事件; _handleTabClick(key){ this.props.ButtonClick(key); } _renderList() { let result = []; const channels = this.state.channels; for(let i in channels) { if(channels[i].attval == 1 || channels[i].attval == 2){ result.push( <TabPane tab={`${channels[i].title}`} key={`${parseInt(channels[i].ID)}`}> <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center',border:'none' }}> </div> </TabPane> ) } } return result } _getMore() { this.props.dispatch( routerRedux.push('/moreChannel') ) } render() { return( <div style={{position:'fixed',top:44,zIndex:999,backgroundColor:'#fff',width:(width/7)*6}}> <Tabs defaultActiveKey="1" pageSize={7} onTabClick={(key) => {this._handleTabClick(key)}} swipeable = {false} > {this._renderList()} </Tabs> <p style={styles.moreChannel} onClick={() => this._getMore()}> <img style={{width:26,height:26,marginTop:8,marginLeft:14}} src={require('../../assets/list/addchannel@2x.png')} alt=""/> </p> </div> ) } } const styles = { moreChannel:{ position:'absolute', top:0, right:-width/7, zIndex:9999, width:width/7, height:42, backgroundColor:'#fff', alignItems:'center', justifyContent:'center' } } function indexList({indexList}) { return { indexList }; } export default connect(indexList)(TabButton);
fetch.jsantd
export default function Request(url,body,callback){ fetch(url,{ method: 'POST', mode: "cors", headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify(body) }).then((res) => res.json()).then((res) => { callback(res) }).catch((err) => { console.log(err) }) }
indexTab.jsapp
import React, { Component,PureComponent,PropTypes } from 'react'; import { Tabs, WhiteSpace,ListView,Toast} from 'antd-mobile'; import { routerRedux } from 'dva/router'; import { connect } from 'dva'; import ReactPullLoad,{ STATS } from 'react-pullload'; import TabButton from './TabButton'; import {width,height} from '../common/style'; let devicenum = localStorage.getItem('devicenum') const loadMoreLimitNum = 10; const defaultStyle ={ width: "100%", textAlign: "center", fontSize: "14px", lineHeight: "1.5", paddingTop:"12px", color:'#ccc' } class HeadNode extends PureComponent{ static propTypes = { loaderState: PropTypes.string.isRequired, }; static defaultProps = { loaderState: STATS.init, }; render(){ const { loaderState } = this.props let content = "" if(loaderState == STATS.pulling){ content = "下拉刷新" } else if(loaderState == STATS.enough){ content = "鬆開刷新" } else if(loaderState == STATS.refreshing){ content = "正在刷新..." } else if(loaderState == STATS.refreshed){ content = "刷新成功" } return( <div style={defaultStyle}> {content} </div> ) } } class FooterNode extends PureComponent{ static propTypes = { loaderState: PropTypes.string.isRequired, hasMore: PropTypes.bool.isRequired }; static defaultProps = { loaderState: STATS.init, hasMore: true }; render(){ const { loaderState, hasMore } = this.props let content = "" if(loaderState == STATS.loading){ return( <div style={defaultStyle}> <img src={require('../../assets/state/fail@2x.png')} alt="" style={{width:32,height:40}} /> <span>正在加載喔~</span> </div> ) } else if(hasMore === false){ content = "沒有更多" } return( <div style={defaultStyle}> {content} </div> ) } } class indexTab extends Component { constructor(props) { super(props) this.state = { channels : [], channelid : 1, showT:false, loading : false, hasMore: true, data: [], action: STATS.init, index: loadMoreLimitNum, newsLength:'' } } componentDidMount() { this.getListData(this.state.channelid); } getListData(channelid) { // List fetch('/api/article',{ method: 'POST', mode: "cors", headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify({ channelID: channelid, type: 0, pageSize: 10, dt : 2, action: 1, devicenum:devicenum }) }).then((res) => res.json()).then((res) => { this.setState({ data: res.result.news, newsLength:res.result.news.length }) this.props.dispatch({ type: 'indexList/detailData', payload: res.result.news, }); }).then(() => { setTimeout(() => { this.setState({ showT : true }) },1900) }).then(() => { setTimeout(() => { this.setState({ showT : false }) },2900) }).catch((err) => { console.log(err) }) } handleAction = (action) => { console.info(action, this.state.action,action === this.state.action); if(action === this.state.action){ return false } if(action === STATS.refreshing){//刷新 this.handRefreshing(); } else if(action === STATS.loading){ this.handLoadMore(); } else{ this.setState({ action: action }) } } handRefreshing = () =>{ if(STATS.refreshing === this.state.action){ return false } this.getListData(this.state.channelid) setTimeout(()=>{ this.setState({ action: STATS.refreshed, index: loadMoreLimitNum }); }, 3000) } handLoadMore = () => { if(STATS.loading === this.state.action){ return false } setTimeout(()=>{ if(this.state.index === 0){ this.setState({ action: STATS.reset, hasMore: false }); } else{ fetch('/api/article',{ method: 'POST', headers: { 'Content-Type': 'application/json;charset=UTF-8', 'Accept': 'application/json' }, body: JSON.stringify({ channelID: this.state.channelid, type: 0, pageSize: 10, dt : 2, action: 1, devicenum:devicenum }) }).then((res) => res.json()).then((res) => { this.setState({ data: [...this.state.data,...res.result.news], action: STATS.reset, index: this.state.index - 1 }) this.props.dispatch({ type: 'indexList/detailData', payload: [...this.state.data,...res.result.news], }); }).then(() => { console.log(this.state.showT) setTimeout(() => { this.setState({ showT : true }) },1900) }).then(() => { setTimeout(() => { this.setState({ showT : false }) },2900) }).catch((err) => { console.log(err) }) } }, 3000) this.setState({ action: STATS.loading }) } //跳轉到詳情頁 _routerDetail(index) { localStorage.setItem('detailid',index) this.props.dispatch( routerRedux.push(`/detail/${index}`) ) } //Tab 切換從新調取 ButtonClick(key) { this.getListData(key); this.setState({ channelid:key }) } _renderShow() { if(this.state.showT == true){ if(this.state.newsLength != 0){ return( <p style={styles.more}>更新了{this.state.newsLength}條內容</p> ) }else{ return( <p style={styles.more}>暫無更新推送</p> ) } }else{ return( <p></p> ) } } render(){ const {data,hasMore} = this.state return ( <div> <TabButton ButtonClick = {this.ButtonClick.bind(this)} /> <p style={{width:100,height:80}}></p> <ReactPullLoad downEnough={50} action={this.state.action} handleAction={this.handleAction} hasMore={hasMore} distanceBottom={10} HeadNode={HeadNode} FooterNode={FooterNode} > <ul className="test-ul"> { data.map( (str, index )=>{ if(str.images[0] != ''){ return <li key={index}> <div style={styles.news} onClick = {() => this._routerDetail(index)}> <img src={str.images[0]} style={styles.imgStyle} /> <p style={styles.newsTitle}>{str.title}</p> <p style={{fontSize:12,color:'#ccc',borderWidth:1}}><span style={{color:'#03D7FF'}}>{str.source}</span> | {str.publishTime}</p> </div> </li> }else{ return <li key={index}> <div style={styles.news} onClick = {() => this._routerDetail(index)}> <p style={styles.newsTitle}>{str.title}</p> <p style={{fontSize:12,color:'#ccc',borderWidth:1}}><span style={{color:'#03D7FF'}}>{str.source}</span> | {str.publishTime}</p> </div> </li> } }) } </ul> </ReactPullLoad> <div> </div> {this._renderShow()} </div> ) } } const styles = { more: { width:width, backgroundColor:'#FFDB01', position:'absolute', zIndex:9999, top:86, textAlign:'center', padding:5, fontSize:14, display:'block', }, news: { padding:15, justifyContent:'center', alignItems:'center' }, imgStyle: { width:width-30, //height:100 }, newsTitle: { fontSize:18, marginTop:10, marginBottom:10 }, moreTab: { width:width-(width/7)*6, height:43, backgroundColor:'#fff', position: 'absolute', justifyContent:'center', alignItems:'center', top:44, right:0, zIndex:9999 } } function indexList({ indexList }) { return { indexList }; } export default connect(indexList)(indexTab);
好啦 上述就是整個首頁的主要代碼,知道如何建立項目的大家能夠嘗試啦~~~cors