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);

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章