第04课:组件和商品详情

知识点:

  • 使用路由跳转内页
  • 开发完整的商品详情页
  • 弹出选择数量

前面的代码已经加入 Git 仓库,链接地址详见这里,将项目放在本地的同学也可以试着将代码放到仓库里,这个地方可以使用单独的分支合并到 master,也可以直接覆盖带 master 分支。

为了能够更直观的看到每次提交的代码,我尽量把每一节的内容都做一次提交,备注也会写的非常清楚,另外我也会不定时的增加各种注释到代码里。一般情况只需要切换到不同的提交时间点即可看到当时使用的代码了。

添加页面和跳转

在 src 目录下添加一个新的目录 detail,用来放新加入的详情页,新建 goods.js,并写几行简单的代码。

enter image description here

在 src 下的 index.js 中,将新建的页面加入到路由里。

enter image description here

这样新建的详情页就加入了路由管理,只要在需要跳转的时候执行传入路由的名字就可以了,这里改造 home 页,将几个地方的跳转改成刚才的路由名称就可以了。

enter image description here

点击商品就会发现已经可以跳转到详情页了,但是现在详情页什么都没有,同时也不能返回到上一页。

enter image description here

自定义顶部

在 src 下新建一个 component 目录,用来存放头部组件以及以后会用到的一些其他组件,将组件抽成一个公用的组件是一个非常明智的方法,它会让你省下很多的时间。最好的做法就是做一个兼容很多情况的组件,然后使用继承的方法做一些参数的重载。

enter image description here

改造这个组件,让 iOS 的顶部和安卓的顶部高度一致,把 iOS 顶部的系统组件露出来,默认情况下 iOS 顶部在小图标下面,安卓则有一个系统的顶部横条,小图标不影响正常的界面。

enter image description here

顶部组件默认有一个中间的标题,下面再加一个默认的左侧返回键,返回键使用的是路由组件的 gobanck 方法,右侧给一个自定义右侧按钮的方法。

enter image description here

把这个自定义组件放在详情页,然后给一个 title 值,一个简单的顶部组件就做完了。

enter image description here

刷新页面看效果,点击一下返回键,看看是不是可以用了。

enter image description here

详情页顶部

上半部分包括头图和几个属性介绍。

详情页的所有内容使用 ScrollView 包裹,这是一个比较简单的列表组件,使用非常方便,在列表不长的情况下请尽量使用这个组件。

enter image description here

将路由传进来的参数保存在组件的变量里。由于传入的参数有2个,所有这个地方使用了2个变量,同时后面做判断的时候也要判断2次。

enter image description here

在组件初始化之后调用接口,将接口返回的数据存入组件的 state 中,这里注意把 state 中的变量提前写好,减少不必要的 bug。

enter image description here

在最上面添加一个商品图片,然后接着添加价格等信息。

enter image description here

enter image description here

到这里,详情页的简单信息就实现了,后面再添加一个详细的商品信息就可以了。

enter image description here

这里需要注意的是,接口返回的图片有大有小,这里做了一个处理,图片太大的话就缩小一些。

enter image description here

最终效果和正常的电商 App 就很相似了,如果有特殊的样式还可以再自己调整。

4d48a070-1a19-11e8-9971-a10b6269e5d3

上面的开发完成之后图片是同时加载的,导致有时候上部分的图片显示延迟,后面优化的时候会优化这种情况。

购买和加入购物车

展示的界面有了,下面再加上加入购物车、购买等按钮就可以了。

按钮要求悬浮在界面的最下方,所以要将这几个按钮放在 ScrollView 的后面,放在里面虽然也可以做到,但是非常不推荐,这样会增加渲染难度。

enter image description here

这里有3个按钮,分别是购物车、立即购买和分享商品。

ba8e33b0-1a1f-11e8-9971-a10b6269e5d3

购买弹出层

点击立即购买按钮不会直接跳转到下单页,这里会弹出一个简单的选择数量的页面。在 RN 中如果需要使用这样的一个层就需要用 Modal 组件来做,Modal 在 RN 中是一个单独的 view 层,默认覆盖在所有的页面上面。

enter image description here

这里设置 Modal 不使用默认的动画、全完透明,给 onRequestClose 添加一个默认的方法,不然会在手机上报错。

首先给 Modal 加一个内容层,这一层的主要作用是自己做遮罩的样式,这里是一个半透明的黑色遮罩,内部加一层点击区域,效果等于再点击黑色透明层的时候能够关掉弹出层。

``` javascript <View style={SpecificationsStyle.warp}> <TouchableOpacity activeOpacity={0.9} style={ { width: px(750), flex: 1 }} onPress={() => this.setState({ priceBoxStatus: false })}></TouchableOpacity> </View>

接下来开始写商品简略信息,包括商品小图、价格。

![enter image description here](http://images.gitbook.cn/f016c6d0-1a3a-11e8-9971-a10b6269e5d3)

下面再加一层用来放选择商品数量和购买按钮。

![enter image description here](http://images.gitbook.cn/4549d7a0-1a3b-11e8-9971-a10b6269e5d3)

最后把几个事件实现一下。

javascript //购买方法 openbuy() { this.setState({ priceBoxStatus: true }) } //数量减少 reduce() { if (this.state.buyNumber == 1) return; let buyNumber = Number(this.state.buyNumber) || 2; if (isNaN(buyNumber)) buyNumber = 2; this.setState({ buyNumber: --buyNumber }) } //改数量 changeNumber(num) { num = Number(num); if (isNaN(num)) num = 1; if (num > this.state.limitStock) { num = 1 toast(库存不足); } this.setState({ buyNumber: num }); } //增加数量 plus() { if (this.state.isBuyLimit == 1 && this.state.buyNumber >= this.state.buyLimitNum) { toast(该商品为限购商品,${this.state.buyLimitMsg}); return; } if (this.state.buyNumber >= this.state.limitStock) { toast(库存仅剩${this.state.limitStock}件); return; } let qty = this.state.buyNumber || 1; if (isNaN(qty)) qty = 1; this.setState({ buyNumber: ++qty }) }

最终效果如图所示,点击立即购买按钮即可弹出这一个弹出层,弹出层可以选择数量,默认保持数量为1,受库存以及最大可选择的数量影响,也可以直接点击按钮跳转到购买页。

<img src="http://images.gitbook.cn/bf604470-1a3b-11e8-9971-a10b6269e5d3"  width = "70%" />

下面是最终的 goods.js 文件的代码:

javascript 'use strict';

import React from 'react'; import { StyleSheet, View, Text, TouchableWithoutFeedback, TouchableOpacity, ImageBackground, Image, ScrollView, Platform, Modal, TextInput } from 'react-native'; import { log, logWarm, logErr } from '../utils/log' import request from '../utils/request' import px from '../utils/px' import toast from '../utils/toast' import Header from '../component/header'

export default class extends React.Component {

constructor(props) {
    super(props);
    this.state = {
        image: "",
        labelList: [],
        goodsShowName: "",
        goodsShowDesc: "",
        salePrice: 0,
        discount: '10',
        marketPrice: 0,
        isInBond: 0,
        isForeignSupply: 0,
        taxation: 0,
        detail: {
            mobile_detail: { list: [] }
        },
        priceBoxStatus: false,
        smallImage: '',
        buyNumber: 1,

    };
    this.id = this.props.navigation.state.params.id;
    this.sku = this.props.navigation.state.params.sku;
}
render() {
    return <View style={
  { fl
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯狂紫萧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值