react+flux 仿淘宝购物车
之前用react写了个表格的单表组件,然后在网上又看到别人家写的一些表格组件,瞬间感觉自己弄的东西好low。不过在写表格组件的时候遇到过一个关于react单向数据流传递的问题,通过一层一层子组件传递完成。而在网上却看到说可以用flux这个的store来方便实现。所以今天特地来实际操作一把,浅鄙见识大家多多指教。
目录结构
这是flux官方推荐的目录结构,其中组件放在components当中,stores中实现数据结构的存储,actions实现控制器的功能。这样就可以实现一个前端的mvc模型。因为react在前段将view层做得很好,不能单靠它实现mvc,所以facebook就又来了个flux两个组合实现一个前端mvc模型。其中app是启动应用。
具体代码
说了这么多,还是赶紧上代码。
先看看stores中存储的的东西。
/*
*购物车商品模块
*/
var AppDispatcher = require('../dispatcher/AppDispatcher');
var EventEmitter = require('events').EventEmitter;
var Constants = require('../constants/Constants');
var assign = require('object-assign');
var CHANGE_EVENT = 'change';
var _moneyCateray = {};
var _storage = localStorage;
_moneyCateray = JSON.parse(_storage.getItem('_moneyCateray'));
/**
*添加购物车商品
*/
function countsPur(purchase){
/**
*初始化检测
*/
if(isEmpty()){
_moneyCateray[purchase.id] = {
price:0,
count:1,
detail:purchase
};
_moneyCateray[purchase.id].price += parseFloat(purchase.price);
_storage.setItem('_moneyCateray',JSON.stringify(_moneyCateray));
return;
}
/**
*查看是否有同类单品
*/
var flag = 0;
for(var i in _moneyCateray){
if(i == purchase.id){
flag = 1;
break;
}
}
/**
*将单品价格分类叠加
*/
if(flag){
_moneyCateray[purchase.id].price += parseFloat(purchase.price);
_moneyCateray[purchase.id].count += 1;
}
else{
_moneyCateray[purchase.id] = {
price:0,
count:1,
detail:purchase
};
_moneyCateray[purchase.id].price += parseFloat(purchase.price);
}
_storage.setItem('_moneyCateray',JSON.stringify(_moneyCateray));
}
/**
*删除商品
*/
function deletePur(id){
delete _moneyCateray[id];
_storage.setItem('_moneyCateray',JSON.stringify(_moneyCateray));
}
/**
*删除一件商品的数量
*/
function deleteCount(id){
if(_moneyCateray[id].count!=0){
_moneyCateray[id].count -= 1;
}else{
_moneyCateray[id].count = 0;
}
_storage.setItem('_moneyCateray',JSON.stringify(_moneyCateray));
}
/**
*检测_moneyCateray是否为空
*/
function isEmpty(){
for(var i in _moneyCateray){
return false;
}
return true;
}
var Store = assign({}, EventEmitter.prototype, {
/**
*获取总价
*/
getMoney:function(){
return JSON.parse(_storage.getItem('_moneyCateray'));
},
/**
*侦听事件变化
*/
emitChange: function() {
this.emit(CHANGE_EVENT);
},
addChangeListener: function(callback) {
this.on(CHANGE_EVENT, callback);
},
removeChangeListener: function(callback) {
this.removeListener(CHANGE_EVENT, callback);
}
});
/**
*注册事件
*/
AppDispatcher.register(function(action) {
var purchase;
switch(action.actionType) {
case Constants.PURCHASE_ADD:
purchase = action.purchase;
if (purchase !== '') {
countsPur(purchase);
Store.emitChange();
}
break;
case Constants.PURCHASE_DELETE:
deletePur(action.id);
Store.emitChange();
break;
case Constants.PURCHASE_SUB:
deleteCount(action.id);
Store.emitChange();
break;
default:
// no op
}
});
module.exports = Store;
其中AppDispatcher是flux推荐的用来注册事件的,我个人感觉是通过这个来实现控制器功能,调用相应的函数功能。
下面来看看ui组件部分的代码
上面是把组件分拆出来的,如下图
将组件分拆,react官网上也这么推荐这样将一个组件尽量分拆出来http://facebook.github.io/react/docs/thinking-in-react.html。
单个商品
var React = require('react');
//var Actions = require('../actions/Actions');
var Per = React.createClass({
getInitialState: function(){
/**
*商品id,价格,详情,图片地址
*/
return {
id:this.props.id,
price:this.props.purchase.price,
detail:this.props.purchase.detail,
url:this.props.purchase.url,
}
},
render: function(){
var price = this.state.price;
return(
<div className="per">
<img src={this.state.url} />
<h3>¥<span>{(parseFloat(price)).toFixed(2)}</span></h3>
<div className="title">{this.state.detail}</div>
<a href="javascript:void(0)" className="button orange addcart" onClick={this._OnSave}>加入购物车</a>
</div>
);
},
_OnSave: function(){
this.props.OnSave(this.state);
}
});
module.exports = Per;
商品列表
/*
*购物列表
*/
var React = require('react');
var Per = require('./Per');
var Actions = require('../actions/Actions');
var Store = require('../stores/purchase');
var PerList = React.createClass({
getInitialState: function(){
/**
*商品id,价格,详情,图片地址
*/
return {
list:this.props.lists
};
},
componentWillUnmount: function(){
},
componentDidMount: function() {
Store.addChangeListener(this._onChange);
},
componentWillUnmount: function() {
Store.removeChangeListener(this._onChange);
},
render: function(){
var list = [];
var purchase = this.state.list;
for(var i in purchase){
list.push(<Per purchase={purchase[i]} key={i} id={i} OnSave={this._onSave} />);
}
return(
<div className="demo">
{list}
</div>
);
},
_onChange: function() {
//this.setState(getTodoState());
},
_onSave: function(pur){
Actions.addPur(pur);
}
});
module.exports = PerList;
购物车
/*
*购物车列表
*/
var React = require('react');
var Store = require('../stores/purchase');
var Actions = require('../actions/Actions');
var PurchaseItem = require('./PurchaseItem');
var PurchaseCar = React.createClass({
getInitialState: function(){
return {
purchaseCar:Store.getMoney()
};
},
componentDidMount: function() {
Store.addChangeListener(this._onChange);
},
componentWillUnmount: function() {
Store.removeChangeListener(this._onChange);
},
render: function(){
var car = this.state.purchaseCar;
var PuchaseCarList = [];
for(var i in car){
PuchaseCarList.push(
<PurchaseItem
key={i}
purchase={car[i]}
AddItem={this._addItem}
SubItem={this._subItem}
DeleteItem={this._deleteItem}/>);
}
return(
<div>{PuchaseCarList}</div>
);
},
_onChange: function(){
this.setState({purchaseCar:Store.getMoney()});
},
_addItem: function(pur){
Actions.addPur(pur.detail);
},
_subItem: function(id){
Actions.subPur(id);
},
_deleteItem: function(id){
Actions.deletePur(id);
}
});
module.exports = PurchaseCar;
通过上面几块代码就实现了一个简单的前端的mvc模型。具体效果如图