React+dva+webpack+antd-mobile 实战分享(二)
第一篇 https://segmentfault.com/a/11...
在上一篇文章中教给大家了怎么搭建项目的架子;那么今天我们就来说一下项目里的导航和列表的实现
导航
废话不说啦 下面直接给大家讲一下代码
项目用的antd-mobile的框架 应该没什么难度,我相信大家认真看文档的都能布局出来;
TabButton.js
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.js
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.js
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);
好啦 上述就是整个首页的主要代码,知道如何创建项目的你们可以尝试啦~~~
React+dva+webpack+antd-mobile 实战分享(二)的更多相关文章
- Vue2+VueRouter2+webpack 构建项目实战(二):目录以及文件结构
通过上一篇博文<Vue2+VueRouter2+webpack 构建项目实战(一):准备工作>,我们已经新建好了一个基于vue+webpack的项目.本篇文章详细介绍下项目的结构. 项目目 ...
- React+dva+webpack+antd-mobile 实战分享(一)
再看本篇文章之前,本人还是建议想入坑react的童鞋可以选有create-react-app来创建react的项目,因为现在dva和roadhog还不成熟,坑相对要多一些,当然如果你已经做好跳坑的准备 ...
- webpack+vue项目实战(四,前端与后端的数据交互和前端展示数据)
地址:https://segmentfault.com/a/1190000010063757 1.前言 今天要做的,就是在上一篇文章的基础上,进行功能页面的开发.简单点说呢,就是与后端的数据交互和怎么 ...
- [书籍精读]《React Native精解与实战》精读笔记分享
写在前面 书籍介绍:本书由架构师撰写,包含ReactNative框架底层原理,以及与iOS.Android混合开发案例,精选了大量实例代码,方便读者快速学习.主要内容分为两大部分,第1部分" ...
- webpack入门和实战(二):全面理解和运用loader和plugins
您的阅读目录: 一.理解webpack加载器loader 二.理解less-loader加载器的使用 三.理解babel-loader加载器的使用 四.webpack命令行常见使用的操作 五.用web ...
- 《React Native 精解与实战》书籍连载「React 与 React Native 简介」
此文是我的出版书籍<React Native 精解与实战>连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理.React Native 组件布局.组件与 ...
- 十九、React UI框架Antd(Ant Design)的使用——及react Antd的使用 button组件 Icon组件 Layout组件 DatePicker日期组件
一.Antd(Ant Design)的使用:引入全部Css样式 1.1 antd官网: https://ant.design/docs/react/introduce-cn 1.2 React中使用A ...
- 非阻塞同步算法实战(二)-BoundlessCyclicBarrier
本人是本文的作者,首发于ifeve(非阻塞同步算法实战(二)-BoundlessCyclicBarrier) 前言 相比上一 篇而言,本文不需要太多的准备知识,但技巧性更强一些.因为分析.设计的过程比 ...
- webpack入门和实战(一):webpack配置及技巧
一.全面理解webpack 1.什么是 webpack? webpack是近期最火的一款模块加载器兼打包工具,它能把各种资源,例如JS(含JSX).coffee.样式(含less/sass).图片等都 ...
随机推荐
- Python自动化 unittest生成测试报告(HTMLTestRunner)03
批量执行完用例后,生成的测试报告是文本形式的,不够直观,为了更好的展示测试报告,最好是生成HTML格式的. unittest里面是不能生成html格式报告的,需要导入一个第三方的模块:HTMLTest ...
- thinkphp6的一些用法
Thinkphp6笔记一:安装http://www.thinkphp.cn/topic/68371.htmlThinkphp6笔记二:开启多应用模式http://www.thinkphp.cn/top ...
- 分析vue脚手架
执行流程: 执行npm run serve.找到了main.js文件,之后引入Vue.App等等.后来找到App组件,发现里面用到了组件School,于是执行School组件,最终汇总到App组件.通 ...
- tensorflow源码解析之common_runtime-session
目录 核心概念 session session_factory 1. 核心概念 session可以认为是一个执行代理.我们在客户端构建计算图,提供输入,然后把计算图丢给session去执行.因此,se ...
- LGB+XGB+CNN一般写法
现在的比赛,想要拿到一个好的名次,就一定要进行模型融合,这里总结一下三种基础的模型: - lightgbm:由于现在的比赛数据越来越大,想要获得一个比较高的预测精度,同时又要减少内存占用以及提升训练速 ...
- LCD1602----LiquidCrystal库的使用1
一:硬件介绍: 1.引脚定义: 2.屏幕介绍: 1602液晶也叫1602字符型液晶,它是一种专门用来显示字母.数字.符号的点阵型液晶模块.它是由若干个5x7或者5x10的点阵字符位组成,每个点阵字符位 ...
- ArcMap操作随记(5)
1.[栅格转面]等工具的使用 若栅格数据为浮点型,需使用[转为整型]工具,将栅格转为整型,再进行操作. 2.人口密度分布趋势图 使用[核密度分析]工具,也可尝试插值 3.点要素做面 [点集转线][要素 ...
- Spring Data ElasticSearch的使用
1.什么是Spring Data Spring Data是一个用于简化数据库访问,并支持云服务的开源框架.其主要目标是使得对数据的访问变得方便快捷,并支持map-reduce框架和云计算数据服务. S ...
- NaviCat连接提示驱动程序IM004错误
今天一打开NaviCat提示驱动程序IM004错误,百度了好几种方法都不起作用,多次尝试后总结出一套方法: 一.到控制面板--卸载程序--卸载NaviCat Clien 注意可能有多个版本的,2008 ...
- Linux移植实际操作一
@ 目录 *前言 目前看了很多关于"Linux移植"的的各种教程.书籍,看完发现不过是对已有板子.已有驱动进行启用.禁用.参数修改.只能叫做"Linux配置". ...