使用 react-native 写的一个 ShopCart 的 demo
目录:
一、index.android.js
// 定义全局变量global.__APP__ = true; // 用于区分是web应用还是app应用 便于代码多端调用global.__ANDROID__ = true; // android环境中global.__IOS__ = false;// 将所有代码放在src目录下执行,方便android和ios调用require('./src'); // 如果写的是目录,则默认调用目录下小写的index.js文件
二、index.ios.js
// 定义全局变量global.__APP__ = true; // 用于区分是web应用还是app应用 便于代码多端调用global.__ANDROID__ = false;global.__IOS__ = true; // ios 环境中// 将所有代码放在src目录下执行,方便android和ios调用require('./src'); // 如果写的是目录,则默认调用目录下小写的index.js文件
三、Index.js ( 跳转页 )
import React, { Component } from 'react';import { AppState, StyleSheet, View, Button, Text} from 'react-native';const INITIAL_ROUTE = { location:'/splash',}const styles = StyleSheet.create({ root: { flex: 1, justifyContent: 'center', }, text: { textAlign: 'center', fontSize: 18, }});// 导入ShopCartimport ShopCart from './ShopCart';export default class App extends Component { gotoShopCart = () => { // 通过解钩 获取传递的navigator const { navigator } = this.props; // push方法会经过navigator的renderScene方法 navigator.push({ component: ShopCart }); }; render() { return (); }} 这是首页
四、ShopCart.js ( 购物车页面 )
/** * 购物车 */import React, { Component } from 'react';import { AppState, StyleSheet, View, Text} from 'react-native';// 引入observer 使静态数据可读写import { observer } from 'mobx-react/native';// 引入改造后的数据import cartData from '../logics/CartData';// 引入Headerimport Header from '../components/Header';// 引入ItemListimport ItemList from '../components/ItemList';// 引入Footerimport Footer from '../components/Footer';const styles = StyleSheet.create({ root: { flex: 1, },});export default class ShopCart extends Component { render() { // ShopCart具有navigator const { navigator } = this.props; return (); }}
五、组件
1. Circle.js
/** * 勾选框组件 */import React, { Component } from 'react';import { StyleSheet, TouchableOpacity} from 'react-native';const styles = StyleSheet.create({ select: { height: 20, width: 20, borderRadius: 10, borderColor: '#000', borderWidth: StyleSheet.hairlineWidth, }, checked: { backgroundColor: '#f23030', },});export default class Circle extends Component { select = () => { // 通过props,从父组件取出onPress const { onPress } = this.props; // 赋值 let { checked } = this.state; // 值相等的情况,es6的简写 checked:checked,只写一个checked, this.setState({ checked, }); // 判断onPress是否存在,存在则执行下面的代码 onPress && onPress(checked); }; state = { checked: false, }; render() {}}
2.Header.js
/** * 头部组件 * 引用组件 矢量图标 npm install react-native-vector-icons@3.x --save * 原生的组件需要link react-native link */import React, { Component } from 'react';import { AppState, StyleSheet, View, Text, TouchableOpacity} from 'react-native';// 引入矢量图标组件import Icon from 'react-native-vector-icons/FontAwesome';const styles = StyleSheet.create({ root: { flexDirection: 'row', height: 44, backgroundColor: '#F5F5F5', justifyContent: 'space-between', paddingHorizontal: 20, alignItems: 'center', }, text: { textAlign: 'center', fontSize: 18, }, back: { fontSize: 20, color: '#900', }, right: { fontSize: 20, color: 'transparent', }});export default class Header extends Component { goBack = () => { // 通过解钩 获取传递的navigator const { navigator } = this.props; navigator.pop(); }; render() { return (); }} {/*引入Icon组件*/} 购物车 {/*引入Icon组件*/}
3.ItemList.js
/** * 列表组件 */import React, { Component } from 'react';import { StyleSheet, ScrollView} from 'react-native';// 引入Item组件import Item from './Item';const styles = StyleSheet.create({ root: { flex: 1, }});// 引入购物车数据import cartData from '../logics/CartData';export default class ItemList extends Component { render() { // 取出父组件传递的参数 const { cartData } = this.props; // 动态创建组件 return ({ cartData.map((data,index) => { return ); }}- }) }
4.Item.js
/** * 列表子组件 */import React, { Component } from 'react';import { StyleSheet, View, Image, TouchableOpacity, Text} from 'react-native';// 引入observerimport { observer } from 'mobx-react/native';// 引入Circle组件import Circle from './Circle';const styles = StyleSheet.create({ root: { flex: 1, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', padding: 10, height: 100, }, img: { width: 90, height: 90, }, content: { // }, price: { // }, name: { fontSize: 16, }, priceAndControls: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', }, button: { padding: 10, justifyContent: 'center', borderWidth: StyleSheet.hairlineWidth, borderColor: '#000', }, buttonText: { // }});// 监听observer@observerexport default class Item extends Component { check = (checked) => { const { index, cartData } = this.props; cartData.check(checked, index); }; minus = () => { const { index, data: { count }, cartData } = this.props; // 安全检查 if(count > 1){ cartData.minus(index); } }; plus = () => { const { index, data: { count }, cartData } = this.props; cartData.plus(index); }; render() { // 取出父组件传递的值 props上的数据只可读不可写(不可更改) const { index, data: {id,name,count,img,checked} } = this.props; return ({/*勾选框*/} ); }}{/*图片*/} {/*描述*/} {name} ¥{price.toFixed(2)} - {count} +
5.Footer.js
/** * 底部组件 */import React, { Component } from 'react';import { AppState, StyleSheet, View, Text, TouchableOpacity} from 'react-native';// 引入矢量图标组件import Icon from 'react-native-vector-icons/FontAwesome';const styles = StyleSheet.create({ root: { position: 'absolute', bottom: 0, left: 0, // 设置left、right为0,可实现width:100%的效果 right: 0, justifyContent: 'center', flexDirection: 'row', height: 44, backgroundColor: '#F5F5F5', justifyContent: 'space-between', borderTopWidth: StyleSheet.hairlineWidth, // 解决1px问题,专门用来设置边界值 alignItems: 'center', // 元素居中 }, selectWrapper: { flexDirection: 'row', // 设置主轴为横向 alignItems: 'center', marginLeft: 20, }, checked: { backgroundColor: '#f23030', }, selectText: { marginLeft: 5, }, checkout: { backgroundColor: '#f23030', paddingHorizontal: 20, height: 50, justifyContent: 'center', }, checkoutText: { fontSize: 18, color: '#fff', }});// 引入observer组件import { observer } from 'mobx-react/native';// 引入勾选框组件 Circleimport Circle from '../components/Circle';@observerexport default class Footer extends Component { // 构造器 状态 // constructor(props) { // super(props); // this.state = { // // // } // } goBack = () => { // 通过解钩 获取传递的navigator const { navigator } = this.props; navigator.pop(); }; selectAll = (checked) => { // 获取子组件返回值 alert(checked); }; render() { const { cartData } = this.props; return (); }} 全选 总计:¥{cartData.sum.get()} 去结算({cartData.count.get()})
六、数据
CartData.js
/** * 通过observer 将数据变成可变的数据(可读写) */import { observable, computed } from 'mobx';/** * 独立于组件的变量,用于存储组件状态 */const cartData = observable([ { id: '928128', name: '飞利浦(PHILIPS)电吹风机 HP8230 家用大功率恒温护发冷热风', price: 620000, count: 1, img: 'http://img10.360buyimg.com/n7/g14/M06/04/15/rBEhV1HcwMEIAAAAAACwKUjHr8IAAA6egEjTU4AALBB222.jpg!q70.jpg.webp', checked: false, }, { id: '3926802', name: '和情(LOTUS)缤咖时焦糖饼干250g*2袋装', price: 6180000, count: 1, img: 'http://img10.360buyimg.com/n7/s176x176_jfs/t3715/282/1024231787/79825/c65fba1d/581aeeb3N5802976f.jpg!q70.jpg.webp', checked: false },]);// 封装对数据操作的方法cartData.minus = (index) => { cartData[index].count -= 1;};cartData.plus = (index) => { cartData[index].count += 1;};cartData.check = (checked, index) => { cartData[index].checked = checked;};// 在现有的数据上计算结束后得到的结果cartData.count = computed(() => { // reduce 类似击鼓传花 层层叠加 return cartData.reduce((a,b) => { if(b.checked){ return a + b.count; }else{ return a; } // return a + b.checked && b.count; },0);});cartData.sum = computed(() => { // reduce 类似击鼓传花 层层叠加 return cartData.reduce((a,b) => { if(b.checked){ return a + b.count * b.price; }else{ return a; } // return a + b.checked && (b.price * b.count); },0);});export default cartData;
.