在 AJAX 时代,进行请求 API 等网络请求都是通过XMLHttpRequest 或者封装后的框架进行网络请求。而在前端快速发展地过程中,为了契合更好的设计模式,产生了 fetch 框架。 fetch相比XMLHttpRequest,提供更加强大、高效的网络请求方式,所以在 Hybrid App 开发模式中,大量的用到了fetch框架作为网络请求。
在 Chrome 浏览器中已经全局支持了 fetch 函数,打开调试工具,在 Console 中可以进行体验下fetch。先不考虑跨域请求的使用方法,我们先请求同域的资源。例如:
fetch("http://blog.csdn.net/xiangzhihong8").then(function(response){console.log(response)})使用 fetch 的构造函数请求数据后,返回一个 Promise 对象,然后根据具体的实际情况处理。
fetch("http://baidu.com") .then(function(response){ // ... })说明,在请求后的 Response 中,常常有如下返回情况:
Response.status 也就是 StatusCode,如成功就是 200 ;Response.statusText 是 StatusCode 的描述文本,如成功就是 OK ;Response.ok 一个 Boolean 类型的值,判断是否正常返回,也就是 StatusCode 为 200-299 。1.使用get方式进行网络请求,例如:
fetch('http://nero-zou.com/test', { method: 'GET' }).then(function(response) { //获取数据,数据处理 }).catch(function(err) { //错误处理 });2.使用post方式进行网络请求,例如:
let param = {user:'xxx',phone:'xxxxxx'}; fetch(url, { method: 'post', body: JSON.stringify(param) }).then(function(response) { //获取数据,数据处理 });3.其它写法,例如:
try { fetch(url, { method: 'post', body: JSON.stringify(param) }).then(function(response) { //获取数据,数据处理 }); } catch(e) { //捕获异常消息 }4.带header 或其它参数,例如:
fetch(url, { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify({ firstParam: 'yourValue', secondParam: 'yourOtherValue', }) })我们先看看使用fetch并填充界面后的完整效果。
要实现上面的效果,我们需要对数据进行监听,也就是所谓的状态机机制。
state: { discounts: Array<Object>, dataSource: ListView.DataSource }然后我们使用fetch进行网络请求,当有数据返回时,我们更改数据源的数据。
requestDiscount() { fetch(api.discount) .then((response) => response.json()) .then((json) => { console.log(JSON.stringify(json)); this.setState({ discounts: json.data }) }) .catch((error) => { alert(error) }) }那么什么时候出发这个请求呢?当我们界面挂载的时候就触发这个请求,所以我们在componentDidMount调用这个请求。
componentDidMount() { this.requestDiscount(); }请求的接口如下:https://api.meituan.com/group/v1/deal/topic/discount/city/1?ci=1&client=iphone&movieBundleVersion=100&msid=48E2B810-805D-4821-9CDD-D5C9E01BC98A2015-06-17-14-50363&userid=10086&utm_campaign=AgroupBgroupD100Fab_chunceshishuju__a__a___b1junglehomepagecatesort__b__leftflow___ab_gxhceshi__nostrategy__leftflow___ab_gxhceshi0202__b__a___ab_pindaochangsha__a__leftflow___ab_xinkeceshi__b__leftflow___ab_gxtest__gd__leftflow___ab_gxh_82__nostrategy__leftflow___ab_pindaoshenyang__a__leftflow___i_group_5_2_deallist_poitype__d__d___ab_b_food_57_purepoilist_extinfo__a__a___ab_trip_yidizhoubianyou__b__leftflow___ab_i_group_5_3_poidetaildeallist__a__b___ab_waimaizhanshi__b__b1___a20141120nanning__m1__leftflow___ab_pindaoquxincelue__a__leftflow___ab_i_group_5_5_onsite__b__b___ab_i_group_5_6_searchkuang__a__leftflow&utm_content=4B8C0B46F5B0527D55EA292904FD7E12E48FB7BEA8DF50BFE7828AF7F20BB08D&utm_medium=iphone&utm_source=AppStore&utm_term=5.7&uuid=4B8C0B46F5B0527D55EA292904FD7E12E48FB7BEA8DF50BFE7828AF7F20BB08D&version_name=5.7
返回的内容如下:
{ stid: "836121754643660800", data: [ { typeface_color: "#ff9900", position: 0, module: false, maintitle: "今日爆款", type: 1, deputytitle: "5折来按摩", solds: 0, id: 19995, share: { message: "养生名店1折起,最高立减30元,", url: "https://g.meituan.com/app/gfe-app-page-discount/index-mt.html" }, title: "今日爆款", deputy_typeface_color: "#21c0ae", tplurl: "imeituan://www.meituan.com/web?url=https://g.meituan.com/app/gfe-app-page-discount/index-mt.html", imageurl: "http://p0.meituan.net/w.h/feop/0044b4cebe650ada958da3458f51eae833656.png" }, { typeface_color: "#f6687d", position: 0, module: false, maintitle: "电影特惠", type: 1, deputytitle: "神奇女侠", solds: 0, id: 19749, share: { message: "热门大片特惠,福利再来一波>>", url: "http://i.meituan.com/firework/km1495594906" }, title: "电影特惠", deputy_typeface_color: "#c280fc", tplurl: "imeituan://www.meituan.com/web?url=http://i.meituan.com/firework/km1495594906", imageurl: "http://p1.meituan.net/w.h/feop/6d7deddaeecd3b6c1181902616f2b4c028136.png" }, { typeface_color: "#6bbd00", position: 0, module: false, maintitle: "特价出游", type: 1, deputytitle: "泰国跟团清仓", solds: 0, id: 20001, share: { message: "特价出游,泰国跟团清仓", url: "http://i.meituan.com/firework/islandseasonMT" }, title: "特价出游", deputy_typeface_color: "#fc6a56", tplurl: "imeituan://www.meituan.com/web?url=http://i.meituan.com/firework/islandseasonMT", imageurl: "http://p1.meituan.net/w.h/feop/80fe92619a56f760e06e8c84657acb9720105.png" }, { typeface_color: "#06c1ae", position: 0, module: false, maintitle: "今日推荐", type: 1, deputytitle: "品质生活指南", solds: 0, id: 3283, share: { message: "吃喝玩乐全都有,尽在美团网!", url: "http://api.mobile.meituan.com/group/v1/re/p" }, title: "今日推荐", deputy_typeface_color: "#fdb32b", tplurl: "imeituan://www.meituan.com/recommend?url=http://api.mobile.meituan.com/group/v1/re/p", imageurl: "http://p0.meituan.net/w.h/feop/24ab8d4d0c2bd36bb4b95d2a8c0b105236553.png" } ], server: { time: 1496411274 }, paging: { count: 4 } }到此,数据请求基本完成了,接下来就是怎么将数据绘制到界面上的问题。为了方便我们需要自定义一个GridView用来绘制这个九宫格界面。我们在render()中定义一个props来接受请求返回的数据。代码如下:
class GridView extends Component { static defaultProps = { infos: [] } render() { let { infos } = this.props let gridItems = [] for (let i = 0; i < infos.length; i++) { let gridItem = ( <GridItem info={infos[i]} key={i} onPress={() => this.props.onGridSelected(i)}/> ) gridItems.push(gridItem) } return ( <View style={styles.container}> {gridItems} </View> ); } } const styles = StyleSheet.create({ container: { flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-between', borderTopWidth: 1, borderLeftWidth: 1, borderColor: '#e9e9e9' }, }); export default GridView;然后我们在绘制每一个GridItem,这个有点类似于Android的Adapter或者ios的CollectionViewCell。代码如下,不做详细的介绍:
var Dimensions = require('Dimensions'); var screen = Dimensions.get('window'); class GridItem extends Component { render() { let info = this.props.info let title = info.maintitle let color = info.typeface_color let subtitle = info.deputytitle let imageUrl = info.imageurl.replace('w.h', '120.0').replace('http','https') return ( <TouchableOpacity style={styles.container} onPress={this.props.onPress}> <View> <Heading1 style={{ color: color, marginBottom: 10}}>{title}</Heading1> <Heading2 >{subtitle}</Heading2> </View> <Image style={styles.icon} source={{ uri: imageUrl}} /> </TouchableOpacity> ); } } const styles = StyleSheet.create({ container: { flexDirection: 'row', justifyContent: 'center', alignItems: 'center', width: screen.width / 2 - 1, height: screen.width / 4, backgroundColor: 'white', borderBottomWidth: 1, borderRightWidth: 1, borderColor: '#e9e9e9' }, icon: { width: screen.width / 5, height: screen.width / 5, } }); export default GridItem;到此我们就完成了fetch请求并绘制界面的功能。附:本文源码fetch请求二次封装
相关资源:敏捷开发V1.0.pptx