React == 实现简易版购物车
1、几个要点:
为了方便后面使用input type = "checkbox" 实现复选框的选中/不选中,给传递过来的属性要在遍历的时候,单独加上一个新属性 checked
count 属性 默认值 都是1.
state = {
all : false,
sumprice :0,
one : false,
sumcount:0
}
state对象 :
- all -----> 用来定义全选按钮
- sumprice -----> 用来定义总价
- one -----> 用来控制 结算按钮的样式(当选中的其中任何一条购物车条目时候,显示橘色,当没有任何一条选中,显示灰色)
- sumcount ----> 用来显示购物车的总数量,显示在页面中
2、单选框的实现
1)首先是渲染的都是同样的样式,所以在这里传递一个index特别关键,通过index的传递才能够知道操作的是哪条
2)当onchange事件发生的时候,对当前checked属性进行取反。list[index].checked = ! list[index].checked。
3)单选框决定全选框:使用了数组的every方法(只有数组的每一项都满足条件,才会返回true),用所有datalist的单选框都是true的时候,全选按钮才会为true
4)单选框的选中与否决定结算框的样式:one : list[index].checked // 为true的时候,one : true
// 单选 handleChange(index){ var list = [...this.state.datalist] list[index].checked = !list[index].checked // every方法 var every=list.every((item,index)=>{ return item.checked==true; }) // 单选框中如果有一个是 checked的是true就可以 var some = list.some((item,index)=>{ return list[index].checked }) this.setState({ datalist :list, all : every, //全选按钮,只有当所有的list[index]=== true 的时候才会返回true one : some //设定结算框的样式是哪个,根据list[index].checked }) this.SumPrice() }
3、全选按钮的实现
1)当点击全选框,对全选框的状态进行取反
2)点击全选按钮的时候,所有的单选框的为true / false 直接取决的 全选框按钮当前的状态true / false
遍历所有的list[i].checked = all , 把全选框的状态(true/false)直接赋值给所有的list[i].checked 。
3)当全选的时候,结算框的样式直接会跟随变动,当为false,即没有一个购物车条目呗选中,此时结算框的状态为灰色。当为true,结算框为橘色。
<input type="checkbox" onChange={()=>{this.handleAll()}} checked={this.state.all} value=""/> // 全选 handleAll(){ var list = [...this.state.datalist] var all = this.state.all all = ! all //onchange事件发生,就是对当前的状态进行取反 for(var i = 0 ; i < list.length ;i++){ list[i].checked = all // 全选框的状态直接影响所有的单选框,就把全选框的状态赋给所有的单选框即可 } this.setState({ all : all, one : all //全选的状态直接影响结算框的样式 }) this.SumPrice() }
4、购物车数量加减的实现
1)数量增加Add
重要的还是传递对应的index,才能准确地知道操作的是哪个购物车条目
list[index].count++
2)数量减少Minus
还有进行一步判断,当此时购物车的数量已经是1的时候,不允许再继续减了
list[index].count--
list[index].count<1?1:list[index].count
<button className={style.minus} onClick={()=>{this.handleMinus(index)}}>-</button> <input type="text" value={this.state.datalist[index].count||''}/> <button className={style.add} onClick={()=>{this.handleAdd(index)}}>+</button> // 加 handleAdd(index){ // 设定的value= {this.state.datalist[index].count} var list = [...this.state.datalist] list[index].count++; this.setState({ datalist : list, }) this.SumPrice() } //减 handleMinus(index){ // 设定的value= {this.state.datalist[index].count} var list = [...this.state.datalist]; list[index].count-- list[index].count=list[index].count<1?1:list[index].count; this.setState({ datalist : list }) this.SumPrice() }
5、总价的实现
1)遍历所有的datalist,只有当其中每一个checked属性为true的时候(表明已经被勾选上了,此时可以计算),才去计算金额
2)得到所有的总价,还能得到当前选中的数量一共有多少
SumPrice(){ var sum=0 var count = 0; var list = [...this.state.datalist] for(var i =0; i< list.length ;i++){ if(list[i].checked=== true){ sum += list[i].newprice *list[i].count count += list[i].count } } this.setState({ sumprice : sum, sumcount : count //结算个数 }) }
6、当进行 数量 的增加、减少、单选按钮、全选按钮的时候 都要重新调用计算总价的函数。
=============================================================================
完整代码:
JS >
class CartPage extends Component { state = { datalist:[ { "imgUrl":"https://wochu.oss-cn-hangzhou.aliyuncs.com/upload/c8db2f99-d79e-4c4a-97e8-3e95c67a3b2e.jpg", "name": "小青菜350g", "newprice" : "4.5", "oldprice" : "4.9", "checked" :false, "count" :1 }, { "imgUrl":"https://img.wochu.cn/upload/abbc6852-711f-4d09-8e61-216c13505ccd.jpg", "name": "洪湖渔家香辣大闸蟹500g", "newprice" : "15.9", "oldprice" : "39.9", "checked" :false, "count" :1 }, { "imgUrl":"https://wochu.oss-cn-hangzhou.aliyuncs.com/upload/c8db2f99-d79e-4c4a-97e8-3e95c67a3b2e.jpg", "name": "小青菜350g", "newprice" : "4.5", "oldprice" : "4.9", "checked" :false, "count" :1 }, ], all : false, sumprice :0, one : false, sumcount:0 } render() { return ( <div className={style.cartList}> <div className={style.cartListItem}> <ul className={style.shopList} ref="myul"> {/* 对应的每个购物车条目 */} { this.state.datalist.map((item,index)=> <li key={index}> <input type="checkbox" className={style.checkbtn+' '+style.UnChecked} ref="mytext" onChange={()=>{this.handleChange(index)}} checked={item.checked} value="" /> <div className={style.shopImg}> {/* 点击图片跳转到页面详情 */} <div className={style.shopImgShow}> <img src={item.imgUrl} alt=""/> </div> </div> {/* 商品详情 */} <div className={style.shopInfo}> <div className={style.shopTitle}>{item.name}</div> <div className={style.shopCoupen}></div> <div className={style.shopPrice}> <div className={style.price}> <span>¥{item.newprice}</span> <i>¥{item.oldprice}</i> </div> <div className={style.shopSelect}> <button className={style.minus} onClick={()=>{this.handleMinus(index)}}>-</button> <input type="text" value={this.state.datalist[index].count||''}/> <button className={style.add} onClick={()=>{this.handleAdd(index)}}>+</button> </div> </div> </div> </li> ) } </ul> </div> <div className={style.sum}> <input type="checkbox" onChange={()=>{this.handleAll()}} checked={this.state.all} value=""/> <div className={style.checkPrice}> {/* 合算 */} <div className={style.totalPrice}> <span className={style.allsum}>合计</span> <span>¥{this.state.sumprice}</span> </div> {/* 不含运费 */} <div className={style.fee}>(不含运费)</div> </div> {/* 结算按钮 */} <div className={this.state.one?style.btnCheck:style.btnNoCheck}>结算 <span>({this.state.sumcount})</span> </div> </div> </div> ); } // 单选 handleChange(index){ var list = [...this.state.datalist] list[index].checked = !list[index].checked var every=list.every((item,index)=>{ return item.checked==true; }) // 单选框中如果有一个是 checked的是true就可以 var some = list.some((item,index)=>{ return list[index].checked }) this.setState({ datalist :list, all : every, one : some //设定结算框的样式是哪个,根据list[index].checked }) this.SumPrice() } // 全选 handleAll(){ var list = [...this.state.datalist] var all = this.state.all all = ! all for(var i = 0 ; i < list.length ;i++){ list[i].checked = all } this.setState({ all : all, one : all //全选的状态直接影响结算框的样式 }) this.SumPrice() } handleAdd(index){ // 设定的value= {this.state.datalist[index].count} var list = [...this.state.datalist] list[index].count++; this.setState({ datalist : list, }) this.SumPrice() } handleMinus(index){ // 设定的value= {this.state.datalist[index].count} var list = [...this.state.datalist]; list[index].count-- list[index].count=list[index].count<1?1:list[index].count; this.setState({ datalist : list }) this.SumPrice() } SumPrice(){ var sum=0 var count = 0; var list = [...this.state.datalist] for(var i =0; i< list.length ;i++){ if(list[i].checked=== true){ sum += list[i].newprice *list[i].count count += list[i].count } } this.setState({ sumprice : sum, sumcount : count //结算个数 }) } } export default CartPage;
CSS >
.cartList{ background:#f4f5f7; width:100%; top:.99rem; .cartListItem{ width:100%; background:#fff; margin-bottom:.04rem; // 购物车列表 .shopList{ width:100%; // height:1.11rem; padding:0 .09rem; background:#fff; li{ width:100%; height:1.11rem; border-bottom: 1px solid #e6e6e6; background: #fff; // 选中按钮 .checkbtn{ width:.17rem; height:1.11rem; float:left; } // 选中时候的类名 .UnChecked{ background:url("../../../image/cart-img/unselect.png") no-repeat; background-size:100% .25rem; } // 点击图片跳转 .shopImg{ width:1.1rem; height:1.1rem; margin:0 .1rem; float:left; .shopImgShow{ width:1.1rem; height:1.1rem; img{ width:100%; } } } // 购物车商品详情 .shopInfo{ width:2.08rem; height:1.1rem; padding:.1rem 0; float:left; .shopTitle{ width:100%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; height:.3rem; font-size:.14rem; } .shopCoupen{ width:2.08rem; height:.12rem; margin:.1rem 0; } .shopPrice{ width:2.08rem; height:.25rem; //价格 .price{ width:1.08rem; height:.21rem; float:left; span{ font-size:.15rem; color:#f96d16; } i{ font-size:.13rem; color:#999; text-decoration: line-through; font-style:normal; } } // 按钮 .shopSelect{ float:right; width:.775rem; height:.25rem; .minus{ float:left; width:.225rem; height:.25rem; border:0; } input{ float:left; width:.325rem; height:.25rem; text-align: center; border:0; } .add{ float:left; width:.225rem; height:.25rem; border:0; } } } } } } } // 合算 div.sum{ width:100%; height:.5rem; background:#fff; padding-left:.1rem; position:fixed; bottom:.5rem; left:0; input{ height:100%; float:left; } .checkPrice{ float:left; width:1.48rem; height:.41rem; line-height: .41rem; padding:.08rem 0; margin-left:.1rem; // 合计 .totalPrice{ float: left; width:.869rem; height:.36rem; line-height:.36rem; font-size:.16rem; color:#f96d16; .allsum{ font-size:.13rem; color:#333; } } // 不含运费 .fee{ float:left; width:.61rem; font-size:.13rem; color:#999; } } // 结算按钮 .btnCheck{ width:1.15rem; height:.49rem; background:rgb(249, 109, 22); float:right; line-height: .49rem; font-size:.18rem; color:#fff; text-align: center; } .btnNoCheck{ width:1.15rem; height:.49rem; background:rgb(153, 153, 153); float:right; line-height: .49rem; font-size:.18rem; color:#fff; text-align: center; } } }