react + react-router + redux + Ant Design Mobile 移动端H5点餐项目源码

最近在接触react,所以花了点时间做了个小的购物demo,以便熟悉对应的api接口。

点击此处下载源码

具体页面如下:

部分代码:

购物车部分:

import React from 'react';
import { withRouter } from 'react-router-dom';
import { Badge, Modal} from 'antd-mobile';
import style from '../css/List.module.scss';
import store from "@/store/store";
const alert = Modal.alert;
class ShopCar extends React.Component {
  constructor(props) {
    super(props);
    this.addNumber = this.addNumber.bind(this);
    this.delNumber = this.delNumber.bind(this);
    this.payMoney = this.payMoney.bind(this);
    this.state = {
      data: [],
      total: 0
    };
  }
  showDetail(val) {
    // 点击传参跳转
    this.props.history.push({
      pathname: '/goodsDetail',
      query: { detail: val}
    });
  }
  addNumber (index, event) {
    event.stopPropagation();
    this.setState(state => {
      let emp = state.data;
      emp[index].number++;
      this.computedMoney();
      return emp;
    });
  }
  delNumber (index, event) {
    event.stopPropagation();
    this.setState(state => {
      let emp = state.data;
      if (emp[index].number > 0) {
        emp[index].number--;
      } else {
        emp[index].number = 0;
      }
      this.computedMoney();
      return emp;
    });
  }
  payMoney () {
    alert('购买', `总金额 ${this.state.total} RMB,确定要购买吗?`, [
      {
        text: '取消',
        onPress: () => console.log('cancel')
      },
      { 
        text: '确定',
        onPress: () => {
          console.log('ok');
          this.props.history.push({
            pathname: '/paySuccess',
            query: {}
          });
        }
      },
    ])
  }
  computedMoney () {
    let number = 0;
    if (this.state.data.length) {
      this.state.data.forEach(item => {
        number += (item.number * item.price);
      });
      this.setState({
        total: number
      });
    }
  }
  componentDidMount() {
    console.log(store.getState);
    if (store.getState && store.getState().data) {
      console.log(store.getState());
      this.setState({
        data: store.getState().data
      });
      setTimeout(() => {
        this.computedMoney();
      }, 30);
      store.subscribe(() => {
        this.computedMoney();
      });
    }
  }
  render() {
    let arr = [...this.state.data];
    let GoodsList = arr.map((item, index) => (
      <li key={index} onClick={this.showDetail.bind(this, item)}>
        <div className={style.img}>
          <img src={item.img} alt=""/>
        </div>
        <div className={style.content}>
          <h5>{item.des}{item.id}</h5>
          <p>
            <span>¥ <strong>{item.price}</strong> RMB</span>
            <Badge text="NEW" style={{ marginLeft: 5, padding: '0 3px', backgroundColor: '#21b68a', borderRadius: 2 }}></Badge>
          </p>
          <p>
            <button onClick={this.addNumber.bind(this, index)} className={style.addBtn}>+</button>
            <input type="text" value={item.number} className={style.number}/>
            <button onClick={this.delNumber.bind(this, index)} className={style.delBtn}>-</button>
          </p>
        </div>
      </li>
    ));
    if (arr.length > 0) {
      return (
        <div className={style.main}>
          <ul className={style.listItem}>
            {GoodsList}
          </ul>
          <div className={style.paymoney}>
            <span>总价: <strong>{this.state.total}</strong> RMB</span>
            <span onClick={this.payMoney.bind(this)}>去付款</span>
          </div>
        </div>
      );
    } else {
      return (
        <div>
          <h2 style={{marginTop: 100, fontSize: 25, color: '#ccc'}}>没有添加商品</h2>
        </div>
      );
    }
    
  }
}

export default withRouter(ShopCar);

列表部分:

import React from 'react';
import { withRouter } from 'react-router-dom';
import { Badge } from 'antd-mobile';
import style from '../css/List.module.scss';
import { goodData } from  '../data/goodsListData';
import store from "@/store/store";
import {setAction, getAction, setShopCar} from '@/store/action';
class List extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      goodData,
      shopCarList: []
    };
  }
  // 获取state的数据
  getStore () {
    store.dispatch({type: getAction.type});  // 触发action
    let val = store.getState();
    this.setState({
      storeMsg: JSON.stringify(val)
    })
  }
  // 设置state的数据
  setStore (val) {
    // 将值传入action里面在里面就可以获取到对应的值
    store.dispatch({type: setAction.type, val});
    // this.setState({
    //   storeMsg: JSON.stringify(store.getState().data)
    // });
    // store.subscribe(() => {
    //   console.log(store.getState())
    // });
  }
  addShopCar (index, item, event) {
    event.stopPropagation();
    this.setState(state => {
      let emp = {...state};
      // 如果选中了,移除掉购物车的内容
      if (emp.goodData[index].selected) {
        this.filterGoods(emp.goodData[index].id, emp.shopCarList);
      } else {
        let val = item;
        val.number = 1;
        emp.shopCarList.push(val);
      }
      emp.goodData[index].selected = !emp.goodData[index].selected;
      return emp;
    });
    this.setStore(this.state.shopCarList);
    console.log(store.getState());
  }
  // 根据id过滤购物车的商品
  filterGoods = (id, arrList) => {
    arrList.forEach((item, index) => {
      if (item.id === id) {
        arrList.splice(index, 1);
      }
    });
  }
  
  showDetail(val) {
    // 点击传参跳转
    this.props.history.push({
      pathname: '/goodsDetail',
      query: { detail: val}
    });
  }
  componentDidMount() {
    // simulate initial Ajax
  }
  render() {
    let arr = [...this.state.goodData];
    let GoodsList = arr.map((item, index) => (
      <li key={index} onClick={this.showDetail.bind(this, item)}>
        <div className={style.img}>
          <img src={item.img} alt=""/>
        </div>
        <div className={style.content}>
          <h5>{item.des}{item.id}</h5>
          <p>
            <span>¥ <strong>{item.price}</strong> RMB</span>
            <Badge text="NEW" style={{ marginLeft: 5, padding: '0 3px', backgroundColor: '#21b68a', borderRadius: 2 }}></Badge>
          </p>
          <p>
            <span>好评数({item.goods})</span>
            <button className={item.selected ? style.active : ''} onClick={this.addShopCar.bind(this, index, item)}>{item.selected ? '已选' : '选择'}</button>
          </p>
        </div>
      </li>
    ));
    return (
      <div className={style.main}>
        <ul className={style.listItem}>
          {GoodsList}
        </ul>
      </div>
    );
  }
}

export default withRouter(List);

详情部分:

import React from  'react';
import style from './css/goodsDetail.module.scss';
import { Button, Modal} from 'antd-mobile';
import HeaderBar from './components/Header';
import { withRouter } from 'react-router-dom';
const alert = Modal.alert;
// const alertInstance = alert('Delete', 'Are you sure???', [
//   { text: 'Cancel', onPress: () => console.log('cancel'), style: 'default' },
//   { text: 'OK', onPress: () => console.log('ok') },
// ]);
class goodsDetail extends React.Component {
  constructor () {
    super();
    this.state = {
      title: '详情页',
      detail: {
      }
    };
  }
  componentDidMount () {
    console.log(this);
    let detail = this.props.location.query.detail;
    this.setState({
      detail
    });
  }
  render () {
    return (
      <div>
        <HeaderBar title={this.state.title}/>
        <div className={style.detailBox}>
          <img src={this.state.detail.img} alt=""/>
          <div className={style.content}>
            <h1>{this.state.detail.des}</h1>
            <h3>¥ {this.state.detail.price} RMB</h3>
            <p>评论数:{this.state.detail.goods}</p>
            <Button type="warning" onClick={() =>
              alert('购买', '确定要购买吗?', [
                { text: '取消', onPress: () => console.log('cancel') },
                { text: '确定', onPress: () => console.log('ok') },
              ])
            }>购买</Button>
          </div>
        </div>
      </div>
    );
  }
}
export default withRouter(goodsDetail);

首页部分:

import React from 'react';
import { withRouter } from 'react-router-dom';
import Banner from './components/Banner';
import FooterBar from './components/Footer';
import HeaderBar from './components/Header';
import List from './components/List';
import style from './css/antMobile.module.scss';
import'./css/reset.scss';
import'./css/base.scss';
class antMobile extends React.Component {
  constructor() {
    super();
    this.state = {
      collapsed: false
    };
  }
  componentWillMount () {
  }
  toggle = () => {
    this.setState({
      collapsed: !this.state.collapsed
    });
  };

  render() {
    return (
      <div className={style.antMobile}>
        <HeaderBar/>
        <Banner/>
        <List/>
        <FooterBar/>
      </div>
    );
  }
}
export default withRouter(antMobile);
发布了165 篇原创文章 · 获赞 139 · 访问量 38万+

猜你喜欢

转载自blog.csdn.net/CodingNoob/article/details/95043619