React-Native学习之路(13) - 购物车的实现 + (Mobx状态管理)

(一) :知识点准备:

(1) reduce函数:性能比for和while好

(1)
array.reduce(callbackfn,[initialValue])
(2)
function callbackfn(preValue,curValue,index,array){}
( preValue:上一次调用回调返回的值,或者是提供的初始值(initialValue))
( curValue:数组中当前被处理的数组项 )
( index:当前数组项在数组中的索引值 )
没有初始值,数组中第一项为preValue,第二项为curValue,所以index从1开始。
有初始值,初始值为preValue,数组第一项为curValue,所以index从0开始。
( array:调用reduce() 方法的数组 )
--------------------------------------------------------------
例子一:(无初始值)
var arr = [0,1,2,3,4]; 
arr.reduce(function (preValue,curValue,index,array) { return preValue + curValue; });
 // 10
--------------------------------------------------------------
例子二:(有初始值)
var arr = [0,1,2,3,4]; 
arr.reduce(function (preValue,curValue,index,array) { return preValue + curValue; }, 5); 
//15

http://www.w3cplus.com/javascript/array-part-8.html

(2) Math.round() ,Math.floor() ,Math.ceil的区别

Math.round() 四舍五入
Math.ceil() 向上取整
Math.floor() 向下取整

(3) Math.random()

返回介于 0 ~ 1 之间的一个随机数。
( random:是随机数的意思 )
--------------------------------
 Math.round(Math.random() * 100000)/100,

(4) toFixed()

toFixed() 方法可把 Number 四舍五入为指定小数位数的数字。
--------------------------------
如: toFixed(1)  四舍五入为一位小数位

(5) slice()函数

  • slice() 方法可从已有的数组中返回选定的元素。
arrayObject.slice(start,end)
-----------
start : 必需。规定从何处开始选取。
如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推。
-----------
end:可选。规定从何处结束选取。
-----------
例子:
dataSource = { this.ds.cloneWithRows(this.Cart.item.slice(0) ) }
//从第0项开始选取

(二) :mobx状态管理:

(1) 安装

  • (1) 安装mobx
npm install mobx --save
  • (2) 安装mobx-react
npm install mobx-react --save
  • (3) 为了使用ES7的语法,我们还需要安装三个babel插件
npm install
babel-plugin-transform-decorators-legacy 
babel-plugin-syntax-decorators
babel-preset-react-native-stage-0 --save-dev
  • (4) 现在你的工程目录下应该有.babelrc文件(如果没有可自行创建),修改文件的内容为:
{
  "presets": ["react-native"],
  "plugins": [
    "syntax-decorators",   //这个也需要的
    "transform-decorators-legacy"
  ]
}

(2) mobx相关知识点

(1) mobx

  • observable 被观察者
  • computed 计算属性,注意这里是属性
  • action 函数

(2) mobx-react/native

  • observer 观察者

(3) useStrict(true);严格模式
(详细) http://www.jianshu.com/p/505d9d9fe36a
http://www.jianshu.com/p/3c818b107858

购物车详细代码:


效果图.gif

效果图

完整代码:

/**
 * Created by WOOW.WU on 2017/7/16.
 */
/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { PropTypes, Component } from 'react';
import {
    AppRegistry,
    StyleSheet,
    Text,
    View,
    ListView,
    Image,
    TouchableOpacity,
    Dimensions,
    Modal,
} from 'react-native';

import { observable, computed, action, useStrict } from 'mobx';
import { observer } from 'mobx-react/native';

useStrict(true);
// import Icon from 'react-native-vector-icons/Ionicons';
// import Icon2 from 'react-native-vector-icons/MaterialCommunityIcons';

const { width, height } = Dimensions.get('window');

class CartItem {
    name = '';
    price = 0;
    detail = '';
    img = '';

    @observable
    isSelect = false;



    @observable
     count = 0;

    constructor(name,price,detail,img){   //初始化数据
        this.name = name;
        this.price = price;
        this.detail = detail;
        this.img = img;

    }

    @action
    inc = () => {
        ++this.count;  //增加和选中状态同步
        this.isSelect = true;
    }

    @action
    dec = () => {
        if( this.count > 0) {
            --this.count;
            this.isSelect = true;
        }else{
            this.isSelect = false;
            this.count = 0;
        }
    }

    @action
    selected = () => {  //切换选中的状态,选中+1,未选中count为0
        this.isSelect = !this.isSelect;
        if(this.isSelect){
            ++this.count
        }else{
            this.count = 0;
        }
    }


}


class Cart {
    //被观察者
    @observable
        item = [];

    //注意这里new CartItem实例化,传参
    constructor() {
        this.item.push( new CartItem("八宝丹","500.00","0.3*1粒/盒",'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1502445576159&di=7be6d7fb59760357f08c2e3e7e1ac963&imgtype=0&src=http%3A%2F%2Fwww.jzj.cn%2Fjup%2Fpro%2Fat%2FJ201634_1185080623.jpg') )
        this.item.push( new CartItem("福禄胶囊",'20.00',"0.3*1粒/盒",'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1502635549043&di=0348d8b05b0b7096fe4bacf4843100a8&imgtype=jpg&src=http%3A%2F%2Fimg1.imgtn.bdimg.com%2Fit%2Fu%3D3067211693%2C4169374304%26fm%3D214%26gp%3D0.jpg') )
        this.item.push( new CartItem("杜仲双降袋泡剂",'30.00',"0.8*1粒/盒",'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1502445882398&di=0cfca8dc0e0f682a1ebab87db21ae271&imgtype=0&src=http%3A%2F%2Fp4.maiyaole.com%2Fimg%2F201607%2F28%2F330_20160728161743758.jpg') )
        this.item.push( new CartItem("豨莶通栓丸",'80.00',"0.2*1粒/盒",'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1502446144560&di=e9320f632932641b65dea83b5fb97471&imgtype=0&src=http%3A%2F%2Fwww.315jiage.cn%2Fupload%2F2016-05%2F16050514411057.jpg') )
        this.item.push( new CartItem("天芪降糖胶囊",'60.00',"2.8*10粒/盒",'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1502446107003&di=7ae286f58b410ce05160f427031ed4cd&imgtype=0&src=http%3A%2F%2Fimg01.img.ehaoyao.com%2Fdata%2Fgoodscenter%2Fimges%2Fmanager%2FCBG216001G_54281%2F20160912170326_69_gw_047.jpg') )
    }
    //总数量
    @computed
        get count() {
            return this.item.reduce( (a,b) => a + b.count, 0)
    }
    //总价
    @computed
        get price() {
            return this.item.reduce( (a,b) => a + (b.price * b.count),0 )
    }




}

@observer  //观察者,观察被观察这observable的状态变化
class Item extends Component {
    static propTypes = {
        data: PropTypes.instanceOf(CartItem),
    };

    render() {
        const { data } = this.props;//接受父组件的传值

        return(
            <TouchableOpacity onPress = { data.selected } activeOpacity={1}>
            <View style={ data.isSelect
                ?
                {backgroundColor:'#ccf3ff',flexDirection:'row',paddingLeft:14,paddingRight:14,paddingTop:20,paddingBottom:20,borderBottomWidth:1,borderBottomColor:'rgba(0,0,0,0.1)'}
                :
                {flexDirection:'row',paddingLeft:14,paddingRight:14,paddingTop:20,paddingBottom:20,borderBottomWidth:1,borderBottomColor:'rgba(0,0,0,0.1)'}
            }>

                <View style={{ padding: 2,justifyContent:'center',alignItems:'center',marginRight: 20}}>
                    {
                        data.isSelect ?
                            <Image source={ require('../radio1.png') } style={{width:28,height:28}} ></Image>
                            :
                            <Image source={ require('../radio2.png') } style={{width:28,height:28}} ></Image>
                    }
                </View>

                {/*每个item中的药品图片*/}
                <View style={{ width:150,height:150,borderRadius:20,borderWidth:1,borderColor:'rgba(0,0,0,0.3)',justifyContent:'center',alignItems:'center'}}>
                    <Image source={{ uri: data.img }} style={{ width:130,height:120}}></Image>
                </View>
                <View style={{ flexDirection:'column',justifyContent:'space-around',marginLeft:20,alignItems:'flex-start'}}>
                    <View>
                        <Text style={{fontSize:20}}> { data.name } </Text>
                    </View>

                    <View style={{ marginLeft: 2 }}>
                        <Text>{ data.detail }</Text>
                    </View>

                    <View style={{ flexDirection:'row'}}>

                        <TouchableOpacity onPress={ data.inc} activeOpacity={1}>
                            <View style={{ borderWidth:1,
                                    borderColor:'rgba(0,0,0,0.4)' ,
                                    width:40,
                                    height:40,
                                    borderTopLeftRadius:8,
                                    borderBottomLeftRadius:8,
                                    justifyContent:'center',
                                    alignItems:'center'
                                }}>
                                    <Text style={{ fontSize:18 }}>+</Text>
                            </View>
                        </TouchableOpacity>

                            <View style={{ backgroundColor:'rgba(0,0,0,0.1)',
                                width:60,
                                height:40,
                                justifyContent:'center',
                                alignItems:'center',
                            }} >
                                <Text style={{fontSize: 20}}>{ data.count }</Text>
                            </View>
                        <TouchableOpacity onPress={ data.dec } activeOpacity={1}>
                            <View style={{
                                borderWidth:1,
                                borderColor:'rgba(0,0,0,0.4)',
                                width:40,
                                height:40,
                                borderTopRightRadius:8,
                                borderBottomRightRadius:8,
                                justifyContent:'center',
                                alignItems:'center'
                            }}>
                                <Text style={{ fontSize:18 }} >-</Text>
                            </View>
                        </TouchableOpacity>
                    </View>


                </View>
                <View style={{ paddingTop:6,flex:1,justifyContent:'flex-end',flexDirection:'row',paddingRight:20}}>
                    <Text style={{ fontSize: 26 ,color:'red'}}> ¥{ data.price } </Text>
                </View>
            </View>
            </TouchableOpacity>
        )
    }
}


@observer
class Info extends Component{

    render() {
        const { cart } = this.props;
        return(
            <View style={{ flexDirection:'row',width:width,height:100,justifyContent:'space-between',backgroundColor:'#454c54'}}>
                <View style={{justifyContent:'center',paddingLeft:20,alignItems:'center'}}>
                    <View style={{ flexDirection:'row',justifyContent:'flex-start',alignItems:'center'}}>
                        <Text  style={{ fontSize:20,color:'white'}} >
                            总金额:
                        </Text>
                        <Text style={{ fontSize:30,color:'#ff7454'}}>
                            ¥{ cart.price }
                        </Text>
                    </View>

                    <View>
                        <Text style={{color:'white'}}>
                            总数量:{ cart.count }
                        </Text>
                    </View>

                </View>
                <View style={{ height:100,
                    width:200,
                    backgroundColor:'#ff7454',
                    justifyContent:'center',
                    alignItems:'center',
                }}>
                    <Text style={{ color:'white', fontSize: 20}}>
                        拟购申请
                    </Text>
                </View>
            </View>
        )
    }
}




export default class ww extends Component {
    constructor(props){
        super(props)
        this.state = {
            show2: false,
            modalVisible: true
        }
    }

    Cart = new Cart();

    ds = new ListView.DataSource({
        rowHasChanged: (v1,v2) => v1 !== v2

    })


    _renderRow(data) {
        return (
            <Item data={ data } />
        ) //父子通信,父组件将data属性传给子组件Item
    }

    _raido() {
        const { cart } = props.
        return (
            this.setState({
               show2 : !this.state.show2
            })
        )
    }

    _showHide( backFromInfo ) {
        this.setSate({
            modalVisible:backFromInfo
        })
    }
    render() {
        return (
            <View style={styles.container}>
                {/*拟购车*/}
                <View style={{ width:width, height:64,justifyContent:'center',alignItems:'center'}}>
                    <Text style={{fontSize:18}}>拟购车</Text>
                </View>

                {/*全选*/}
                <TouchableOpacity
                    activeOpacity={ 1 }
                    onPress={ this._raido.bind(this) }
                >
                    <View style={{ paddingLeft:14,backgroundColor:'#f7f7f7',width:width ,height:50,justifyContent:'flex-start',flexDirection:'row',alignItems:'center'}}>
                        <TouchableOpacity onPress={ Cart.selected }>
                            <View style={{ padding: 2}}>
                            {
                                this.state.show2 ?
                                    <Image source={ require('../radio1.png') } style={{width:28,height:28}} ></Image>
                                    :
                                    <Image source={ require('../radio2.png') } style={{width:28,height:28}} ></Image>
                            }
                            </View>
                        </TouchableOpacity>
                        <Text style={{ fontSize: 18,marginLeft:10}}>
                            全选
                        </Text>
                    </View>
                </TouchableOpacity>




                {/*listView列表*/}
                <ListView
                    dataSource = { this.ds.cloneWithRows(this.Cart.item.slice(0)) }
                    renderRow = { this._renderRow }
                ></ListView>


                {/*底部的购物车总价,总数量*/}

                    <Info cart={ this.Cart } ></Info>

            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: 'white',
    }
});

AppRegistry.registerComponent('ww', () => ww);

http://www.jianshu.com/p/02449397762d
http://www.jianshu.com/p/c581c48a601f
http://www.jianshu.com/p/3b37a58619b6

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,233评论 6 495
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,357评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,831评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,313评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,417评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,470评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,482评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,265评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,708评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,997评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,176评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,827评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,503评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,150评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,391评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,034评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,063评论 2 352

推荐阅读更多精彩内容

  • 前些日子从@张鑫旭微博处得一份推荐(Front-end-tutorial),号称最全的资源教程-前端涉及的所有知识...
    谷子多阅读 4,191评论 0 44
  • 大部分的后端会很很鄙视前端。我也不知道为什么,可能大部分人都会觉得脚本语言根本不算语言。 大多人 会叫我们切图仔,...
    小黑的眼阅读 3,323评论 0 15
  • 我坐在办公楼下的咖啡厅,这家咖啡真难喝,不想再喝了,可以作为辞职的理由吗? 对面的朋友差点笑喷,如果你用这个理由,...
    柿子顾阅读 297评论 0 0
  • 时间管理大师共同的结论就是要事优先,要事可以用青蛙来比喻。吃青蛙就是做要事,每天三件,三是概数,做完三个可以再来三...
    侯东松阅读 195评论 0 0
  • jvm进程 JVM进程可以由bin\jps查看。在命令行下输入jps 由一个jdk文件系统,可以产生很多jvm进程...
    stutterr阅读 226评论 0 0